{"version":3,"file":"app-7cbbc9b2.f584a1446b2fc034d810.bundle.js","mappings":"AAGA","sources":["webpack://lernplattform-admin-frontend/./src/resources/elements/mp-rfg-form/mp-rfg-form.html","webpack://lernplattform-admin-frontend/./src/resources/elements/mp-rfg-preview/mp-rfg-preview.html","webpack://lernplattform-admin-frontend/./src/resources/elements/mp-risi-form/mp-risi-form.html","webpack://lernplattform-admin-frontend/./src/resources/elements/mp-tile-form/mp-tile-form.html","webpack://lernplattform-admin-frontend/./src/resources/elements/multi-select-combo-box/multi-select-combo-box.html","webpack://lernplattform-admin-frontend/./src/resources/elements/navigation-bar/navigation-bar-item.html","webpack://lernplattform-admin-frontend/./src/resources/elements/navigation-bar/navigation-bar-menu.html","webpack://lernplattform-admin-frontend/./src/resources/elements/navigation-bar/navigation-bar.html","webpack://lernplattform-admin-frontend/./src/resources/elements/navigation-tabs/navigation-tabs.html","webpack://lernplattform-admin-frontend/./src/resources/elements/notification-bell/notification-bell.html","webpack://lernplattform-admin-frontend/./src/resources/elements/operation-status-list/operation-status-list-item/operation-status-list-item.html","webpack://lernplattform-admin-frontend/./src/resources/elements/operation-status-list/operation-status-list.html","webpack://lernplattform-admin-frontend/./src/resources/elements/mp-rfg-form/mp-rfg-form.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/mp-rfg-preview/mp-rfg-preview.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/mp-risi-form/mp-risi-form.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/mp-tile-form/mp-tile-form.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/multi-select-combo-box/multi-select-combo-box.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/navigation-bar/menu-entries/index.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/navigation-bar/menus/lecturer-menu.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/navigation-bar/menus/operator-menu.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/navigation-bar/menus/poweruser-menu.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/navigation-bar/menus/provider-menu.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/navigation-bar/menus/teaching-material-menu-entry.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/navigation-bar/navigation-bar-item.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/navigation-bar/navigation-bar-menu.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/navigation-bar/navigation-bar.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/navigation-tabs/navigation-tabs.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/notification-bell/index.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/notification-bell/notification-bell.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/operation-status-list/index.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/operation-status-list/operation-status-list-item/operation-status-list-item.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/operation-status-list/operation-status-list.ts"],"sourcesContent":["// Module\nvar code = \"<template class=\\\"card\\\"> <div class=\\\"card-header\\\"> <h1 class=\\\"card-title\\\" t=\\\"elements.mpRfgForm.mpRfgTitle\\\"></h1> </div> <div class=\\\"card-body\\\"> <alert-message if.to-view=\\\"!block.text\\\" message.to-view=\\\"{ tk: `pages.content-editor.mpRfgSequenceWarning` }\\\" message-style=\\\"alert-warning\\\"></alert-message> <alert-message if.to-view=\\\"errorTk\\\" message.to-view=\\\"{ tk: errorTk }\\\" message-style=\\\"alert-danger\\\"></alert-message> <div class=\\\"row\\\"> <div class=\\\"col-6\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"elements.mpRfgForm.categoryOne\\\"></label> <input class=\\\"form-control\\\" attach-focus blur.trigger=\\\"updateEntries(categoryOne)\\\" keypress.trigger=\\\"handleKeyPress($event, categoryOne)\\\" t=\\\"[placeholder]elements.mpRfgForm.categoryOne\\\" value.two-way=\\\"categoryOne\\\" type=\\\"text\\\"> </div> </div> <div class=\\\"col-6\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"elements.mpRfgForm.categoryTwo\\\"></label> <input class=\\\"form-control\\\" blur.trigger=\\\"updateEntries(categoryTwo)\\\" keypress.trigger=\\\"handleKeyPress($event, categoryTwo)\\\" t=\\\"[placeholder]elements.mpRfgForm.categoryTwo\\\" value.two-way=\\\"categoryTwo\\\" type=\\\"text\\\"> </div> </div> </div> <div class=\\\"row\\\"> <div class=\\\"col-6\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"elements.mpRfgForm.uploadImages\\\"></label> <file-drop-zone class=\\\"mp-rfg-form__dropzone ${!categoryValid(categoryOne) ? 'mp-rfg-form__dropzone--disabled' : ''}\\\" max-files=\\\"10\\\" description-text-tk=\\\"elements.mpRfgForm.dropzonePlaceholder\\\" drop-zone-style=\\\"gallery\\\" show-icon.to-view=\\\"false\\\" has-min-height.to-view=\\\"false\\\" url.to-view=\\\"uploadUrl\\\" upload-callback.to-view=\\\"uploadCallback\\\" added-file-callback.to-view=\\\"addedFileCallback\\\" error-callback.to-view=\\\"uploadErrorCallback\\\" success.delegate=\\\"handleFileUploadSuccess($event, categoryOne)\\\"></file-drop-zone> </div> </div> <div class=\\\"col-6\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"elements.mpRfgForm.uploadImages\\\"></label> <file-drop-zone class=\\\"mp-rfg-form__dropzone ${!categoryValid(categoryTwo) ? 'mp-rfg-form__dropzone--disabled' : ''}\\\" max-files=\\\"10\\\" description-text-tk=\\\"elements.mpRfgForm.dropzonePlaceholder\\\" drop-zone-style=\\\"gallery\\\" show-icon.to-view=\\\"false\\\" has-min-height.to-view=\\\"false\\\" url.to-view=\\\"uploadUrl\\\" upload-callback.to-view=\\\"uploadCallback\\\" added-file-callback.to-view=\\\"addedFileCallback\\\" error-callback.to-view=\\\"uploadErrorCallback\\\" success.delegate=\\\"handleFileUploadSuccess($event, categoryTwo)\\\"></file-drop-zone> </div> </div> </div> <div class=\\\"row\\\"> <div class=\\\"col-6\\\"> <div class=\\\"mp-rfg-form__categories-header\\\"> <p class=\\\"mp-rfg-form__categories-header-text\\\" t=\\\"elements.mpRfgForm.uploads\\\"></p> <p class=\\\"mp-rfg-form__categories-header-text mp-rfg-form__categories-header-text--danger\\\" click.delegate=\\\"removeAllEntries(categoryOneEntries, categoryOne)\\\" t=\\\"elements.mpRfgForm.emptyList\\\"></p> </div> <ul class=\\\"mp-rfg-form__categories-list\\\"> <li class=\\\"mp-rfg-form__categories-entry\\\" repeat.for=\\\"entry of categoryOneEntries\\\"> <x-picture picture.to-view=\\\"entry.picture\\\" class=\\\"mp-rfg-form__categories-entry-img\\\"> </x-picture> <p class=\\\"mp-rfg-form__categories-entry-text\\\">${entry.pictureName}</p> <x-icon class=\\\"mp-rfg-form__categories-entry-icon\\\" click.delegate=\\\"removeRfgEntry(entry.id, categoryOne)\\\" size=\\\"unspecified\\\" icon-type=\\\"custom\\\" icon-name=\\\"System/Close\\\"> </x-icon> </li> </ul> </div> <div class=\\\"col-6\\\"> <div class=\\\"mp-rfg-form__categories-header\\\"> <p class=\\\"mp-rfg-form__categories-header-text\\\" t=\\\"elements.mpRfgForm.uploads\\\"></p> <p class=\\\"mp-rfg-form__categories-header-text mp-rfg-form__categories-header-text--danger\\\" click.delegate=\\\"removeAllEntries(categoryTwoEntries, categoryTwo)\\\" t=\\\"elements.mpRfgForm.emptyList\\\"></p> </div> <ul class=\\\"mp-rfg-form__categories-list\\\"> <li class=\\\"mp-rfg-form__categories-entry\\\" repeat.for=\\\"entry of categoryTwoEntries\\\"> <x-picture picture.to-view=\\\"entry.picture\\\" class=\\\"mp-rfg-form__categories-entry-img\\\"> </x-picture> <p class=\\\"mp-rfg-form__categories-entry-text\\\">${entry.pictureName}</p> <x-icon class=\\\"mp-rfg-form__categories-entry-icon\\\" click.delegate=\\\"removeRfgEntry(entry.id, categoryTwo)\\\" size=\\\"unspecified\\\" icon-type=\\\"custom\\\" icon-name=\\\"System/Close\\\"> </x-icon> </li> </ul> </div> </div> </div> <div class=\\\"card-footer text-right\\\"> <button type=\\\"submit\\\" class=\\\"btn btn-primary\\\" click.delegate=\\\"handleSaveBlock()\\\" t=\\\"globals.save\\\"></button> <button class=\\\"btn btn-secondary\\\" click.delegate=\\\"handleCancelSaveBlock()\\\" t=\\\"globals.cancel\\\"></button> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <div if.to-view=\\\"error\\\" class=\\\"alert alert-danger text-center\\\"> <button-standard icon-type=\\\"custom\\\" class=\\\"d-inline-block\\\" icon-name=\\\"System/Tabler/Refresh\\\" click.delegate=\\\"reloadGameData()\\\" btn-text.to-view=\\\"`error`\\\"></button-standard> </div> <mp-rapid-fire-game if.to-view=\\\"text && !error\\\" data.to-view=\\\"gameData\\\"></mp-rapid-fire-game> <static-block-preview if.to-view=\\\"!text\\\" icon-name=\\\"File/rapid-fire\\\"></static-block-preview> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"card mp-risi-form ${ blockId ? 'mp-risi-form--full-size' : '' }\\\"> <div class=\\\"card-header\\\"> <h1 class=\\\"card-title\\\" t=\\\"pages.content-editor.block.mp-risi\\\"></h1> <button-standard class=\\\"ml-auto\\\" click.trigger=\\\"handleCancelClick()\\\" icon-name=\\\"System/Tabler/X\\\" btn-type=\\\"outline\\\" btn-color=\\\"danger\\\"></button-standard> </div> <div if.to-view=\\\"!blockId\\\" class=\\\"card-body\\\"> <alert-message message.to-view=\\\"{ tk: `pages.content-editor.risiWarning` }\\\" message-style=\\\"alert-warning\\\"></alert-message> </div> <div if.to-view=\\\"blockId\\\" class=\\\"card-body mp-risi-form__body\\\"> <div class=\\\"row\\\"> <div class=\\\"form-group col-12\\\"> <label class=\\\"form-label\\\" t=\\\"elements.mpRisiForm.selectLevel\\\"></label> <select class=\\\"custom-select\\\" value.two-way=\\\"selectedLevelOption\\\" attach-focus> <option repeat.for=\\\"levelOption of levelOptions\\\" model.to-view=\\\"levelOption\\\" t=\\\"elements.mpRisiForm.level\\\" t-params.to-view=\\\"{ level: $index + 1 }\\\"> </option></select> </div> </div> </div> <div class=\\\"card-footer text-right\\\"> <button class=\\\"btn btn-primary\\\" click.delegate=\\\"handleSaveClick()\\\" t=\\\"globals.save\\\"></button> <button class=\\\"btn btn-secondary\\\" click.delegate=\\\"handleCancelClick()\\\" t=\\\"globals.cancel\\\"></button> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"mp-tile-form\\\"> <div repeat.for=\\\"tile of tiles\\\" class=\\\"mp-tile-form__tile-wrapper\\\"> <mp-tile class=\\\"mp-tile-form__tile\\\" tile.to-view=\\\"tile\\\"></mp-tile> <div class=\\\"mp-tile-form__button-wrapper\\\"> <button class=\\\"btn btn-secondary btn-sm\\\" click.delegate=\\\"handleEditTile(tile, $index)\\\" t=\\\"elements.mpTileForm.editTileButton\\\"></button> <button class=\\\"btn btn-danger btn-sm\\\" click.delegate=\\\"handleDeleteTile($index)\\\" t=\\\"globals.delete\\\"></button> </div> </div> <button-standard class=\\\"mp-tile-form__add-button\\\" t=\\\"[btnText]elements.mpTileForm.addTileButton\\\" click.delegate=\\\"handleAddTile()\\\" icon-name=\\\"System/Tabler/Plus\\\" btn-color=\\\"primary\\\"></button-standard> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"multi-select-combo-box ${ isInvalid ? 'multi-select-combo-box--is-invalid' : '' }\\\"> <span data-toggle=\\\"dropdown\\\" ref=\\\"buttonRef\\\"> <div class=\\\"multi-select-combo-box__input-wrapper\\\"> <input type=\\\"text\\\" focus.trigger=\\\"showMenu()\\\" disabled.to-view=\\\"disabled\\\" placeholder.to-view=\\\"placeholder\\\" value.two-way=\\\"searchString\\\" class=\\\"form-control multi-select-combo-box__input\\\"> <safe-icon class=\\\"multi-select-combo-box__search-icon\\\" icon-name=\\\"System/Tabler/Search\\\"></safe-icon> </div> </span> <div class=\\\"dropdown-menu show popper-tooltip ${ show ? '' : 'popper-tooltip--hidden' }\\\" ref=\\\"dropdownRef\\\" role=\\\"dialog\\\"> <div class=\\\"multi-select-combo-box__select-all-wrapper mx-2\\\"> <label class=\\\"custom-control custom-checkbox custom-control-inline form-check d-flex\\\" click.trigger=\\\"selectAllItems()\\\"> <input class=\\\"custom-control-input form-check-input multi-select-combo-box__read-only\\\" type=\\\"checkbox\\\" checked.to-view=\\\"selectedItems.length === totalItems.length\\\"> <span class=\\\"custom-control-label\\\" t=\\\"elements.dropdownSearch.allSelected\\\"></span> </label> <button-standard click.delegate=\\\"hideMenu()\\\" icon-name=\\\"System/Tabler/X\\\" btn-color=\\\"none\\\" icon-color=\\\"text-secondary\\\" btn-size=\\\"tiny\\\"></button-standard> </div> <label if.to-view=\\\"matchingItems.length > 0 && matchingItems.length < totalItems.length\\\" class=\\\"custom-control custom-checkbox custom-control-inline mx-2 d-flex\\\" click.trigger=\\\"selectAllMatchingItems()\\\"> <input class=\\\"custom-control-input form-check-input multi-select-combo-box__read-only\\\" type=\\\"checkbox\\\" checked.to-view=\\\"selectedMatchingItems.length === matchingItems.length\\\"> <span class=\\\"custom-control-label\\\" t=\\\"elements.dropdownSearch.allMatchingSelected\\\"></span> </label> <hr class=\\\"w-100 mt-2 mb-3\\\"/> <label class=\\\"custom-control custom-checkbox custom-control-inline mx-2 d-flex\\\" repeat.for=\\\"item of matchingItems\\\"> <input class=\\\"custom-control-input form-check-input\\\" type=\\\"checkbox\\\" model.bind=\\\"item\\\" change.delegate=\\\"handleSelectedItemsChanged()\\\" checked.bind=\\\"selectedItems\\\"> <span class=\\\"custom-control-label\\\">${item[labelPropertyName]}</span> </label> <label repeat.for=\\\"item of unmatchingItems\\\" class=\\\"custom-control custom-checkbox custom-control-inline mx-2 d-flex\\\"> <input class=\\\"custom-control-input form-check-input\\\" type=\\\"checkbox\\\" model.bind=\\\"item\\\" change.delegate=\\\"handleSelectedItemsChanged()\\\" checked.bind=\\\"selectedItems\\\"> <p class=\\\"text-muted my-0 custom-control-label\\\">${item[labelPropertyName]}</p> </label> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <a if.to-view=\\\"item.routeName\\\" as-element=\\\"router-link\\\" class=\\\"nav-link\\\" to.to-view=\\\"{ name: item.routeName }\\\"> <i if.to-view=\\\"!item.customIcon\\\" class=\\\"fe ${item.icon}\\\"></i> <safe-icon else class=\\\"navigation-bar__custom-icon\\\" icon-name.to-view=\\\"item.icon\\\"></safe-icon> <span t.to-view=\\\"item.tk\\\"></span> <update-counter if.to-view=\\\"itemCount\\\" class=\\\"navigation-bar__update-counter\\\" update-count.to-view=\\\"itemCount\\\"></update-counter> </a> <a if.to-view=\\\"item.externalLink\\\" class=\\\"nav-link\\\" href.to-view=\\\"item.externalLink\\\" target=\\\"_blank\\\"> <safe-icon class=\\\"navigation-bar__custom-icon\\\" icon-name.to-view=\\\"item.icon\\\"></safe-icon> <span t.to-view=\\\"item.tk\\\"></span> </a> <a if.to-view=\\\"item.subMenu\\\" as-element=\\\"navigation-bar-menu\\\" class=\\\"nav-link\\\" is-custom.to-view=\\\"item.customIcon\\\" title-icon.to-view=\\\"item.icon\\\" title-tk.to-view=\\\"item.tk\\\" entries.to-view=\\\"item.subMenu\\\"></a> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"${ isActive ? 'active' : ''}\\\" click.delegate=\\\"handleClick()\\\"> <dropdown-button show-menu.two-way=\\\"showMenu\\\"> <div slot=\\\"button\\\"> <safe-icon if.to-view=\\\"isCustom && titleIcon\\\" class=\\\"navigation-bar__custom-icon\\\" icon-name.to-view=\\\"titleIcon\\\"></safe-icon> <i else class=\\\"fe ${titleIcon}\\\"></i> <span t.to-view=\\\"titleTk\\\"></span> </div> <a repeat.for=\\\"entry of entries\\\" as-element=\\\"router-link\\\" class=\\\"dropdown-item nav-dropdown-link\\\" to.to-view=\\\"{ name: entry.routeName }\\\"> <i if.to-view=\\\"entry.icon && !entry.customIcon\\\" class=\\\"fe ${entry.icon}\\\"></i> <safe-icon if.to-view=\\\"entry.icon && entry.customIcon\\\" class=\\\"navigation-bar__custom-icon\\\" icon-name.to-view=\\\"entry.icon\\\"></safe-icon> <span t.to-view=\\\"entry.tk\\\"></span> </a> </dropdown-button> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"navigation-bar\\\"> <div class=\\\"navigation-bar__wrapper header collapse d-lg-flex p-0 navigation-bar__collapse ${ navBarVisible ? 'show position-absolute w-100' : '' }\\\"> <div class=\\\"navigation-bar__menu container\\\"> <div class=\\\"row align-items-center\\\"> <div class=\\\"col-lg order-lg-first\\\"> <ul class=\\\"nav nav-tabs border-0 flex-column flex-lg-row\\\"> <li repeat.for=\\\"item of activeMenuEntries\\\" class=\\\"nav-item navigation-bar__nav-item\\\"> <navigation-bar-item item.to-view=\\\"item\\\"></navigation-bar-item> </li> <li if.to-view=\\\"hasPendingRoles\\\" class=\\\"nav-item navigation-bar__nav-item\\\"> <a as-element=\\\"router-link\\\" class=\\\"nav-link\\\" to.to-view=\\\"{ name: 'invites' }\\\"><i class=\\\"fe fe-check-circle\\\"></i><span t=\\\"navigation.invites\\\"></span></a> </li> </ul> </div> </div> </div> <div if.to-view=\\\"showBreadcrumbs\\\" class=\\\"container\\\"> <breadcrumbs class=\\\"navigation-bar__breadcrumbs\\\" items.to-view=\\\"breadcrumbs\\\"></breadcrumbs> </div> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"navigation-tabs ${ noBorder ? 'navigation-tabs--no-border' : '' } ${ horizontalPadding ? 'navigation-tabs--padding' : '' }\\\"> <div repeat.for=\\\"tab of tabs\\\" click.delegate=\\\"handleTabSelected(tab)\\\" class=\\\"navigation-tabs__tab ${tab.active ? 'navigation-tabs__tab--active' : 'text-muted'} ${ wideTabs ? 'navigation-tabs__tab--wide' : '' } ${ fillWidth ? 'navigation-tabs__tab--fill-width' : '' } ${ disabled ? 'navigation-tabs__tab--disabled' : '' } ${ fillHeight ? 'navigation-tabs__tab--fill-height' : '' }\\\"> <span if.to-view=\\\"tab.title.titleTk\\\" class=\\\"mb-0 h6\\\" t=\\\"${tab.title.titleTk}\\\" t-params.to-view=\\\"tab.title.titleTkParams\\\"></span> <span if.to-view=\\\"tab.title.titleText\\\" class=\\\"mb-0 h6\\\">${tab.title.titleText}</span> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"notification-bell\\\" click.delegate=\\\"goToMessages()\\\"> <x-icon class=\\\"notification-bell__icon\\\" size=\\\"unspecified\\\" icon-type=\\\"custom\\\" icon-name.to-view=\\\"iconName\\\"></x-icon> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"operation-status-list-item operation-status-list-item--${status}\\\"> <safe-icon class=\\\"operation-status-list-item__icon\\\" icon-name.to-view=\\\"iconName\\\"></safe-icon> <div class=\\\"operation-status-list-item__id\\\">ID ${item.id}</div> <div class=\\\"operation-status-list-item__status\\\">${status}</div> <div class=\\\"operation-status-list-item__message\\\">${item.message}</div> <div if.to-view=\\\"item.downloads.length\\\" class=\\\"operation-status-list-item__downloads\\\"> <div repeat.for=\\\"download of item.downloads\\\" class=\\\"operation-status-list-item__download\\\"> <span t=\\\"elements.operationStatusList.download\\\" t-params.to-view=\\\"{ index: $index + 1 }\\\"></span> <a href.to-view=\\\"download.url\\\">${download.name}</a> </div> </div> <div if.to-view=\\\"showReport\\\" class=\\\"operation-status-list-item__report\\\"> <div repeat.for=\\\"file of reportErrors\\\" class=\\\"operation-status-list-item__report-error\\\"> <span>${file.filename}</span> <span class=\\\"text-danger\\\">${file.errorMessage}</span> </div> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"operation-status-list\\\"> <template if.to-view=\\\"imports.length\\\"> <div class=\\\"operation-status-list__list-header\\\" t=\\\"elements.operationStatusList.imports\\\"></div> <div class=\\\"operation-status-list__import-list\\\"> <operation-status-list-item repeat.for=\\\"import of imports\\\" item.to-view=\\\"import\\\"></operation-status-list-item> </div> </template> <template if.to-view=\\\"exports.length\\\"> <div class=\\\"operation-status-list__list-header\\\" t=\\\"elements.operationStatusList.exports\\\"></div> <div class=\\\"operation-status-list__export-list\\\"> <operation-status-list-item repeat.for=\\\"export of exports\\\" item.to-view=\\\"export\\\"></operation-status-list-item> </div> </template> </template>\";\n// Exports\nexport default code;","import { autoinject, bindable } from 'aurelia-framework';\nimport { ApiError } from 'common/aurelia-classes/Error';\nimport { PictureUploadResponse } from 'common/dto/content/gallery.response';\nimport { IMpRapidfireEntryDto } from 'common/dto/content/methodpool/rapidfire.interface';\nimport { KeyboardKey } from 'common/enum/keyboard.key.enum';\nimport { ArrayUtils } from 'common/utils/ArrayUtils';\nimport { assertNotNullOrUndefined } from 'common/utils/assert';\nimport { DomUtils } from 'common/utils/DomUtils';\nimport { LogUtils } from 'common/utils/LogUtils';\nimport { MethodpoolUtils } from 'common/utils/MethodpoolUtils';\nimport { MethodpoolApiService } from '../../../services/api/MethodpoolApiService';\nimport { GalleryService } from '../../../services/GalleryService';\nimport { IContentEditorBlockEditorBlock } from '../../dialogs/content-editor-block-editor-dialog/content-editor-block-editor-dialog';\nimport { FileDropZoneUploadSuccessEvent } from '../file-drop-zone/file-drop-zone';\n\n/**\n * @event {EditRfgOkEvent} edit-rfg-ok\n * @event {EditRfgCancelEvent} edit-rfg-cancel\n */\n@autoinject()\nexport class MpRfgForm {\n  @bindable() public courseId: number | null = null;\n  @bindable() public block: IContentEditorBlockEditorBlock | null = null;\n  private categoryOne: string = '';\n  private categoryTwo: string = '';\n  private categoryOneEntries: Array<IMpRapidfireEntryDto> = [];\n  private categoryTwoEntries: Array<IMpRapidfireEntryDto> = [];\n  private uploadUrl: string = '/api/pictures/gallery';\n  private errorTk: string | null = null;\n  private domElement: HTMLElement;\n\n  constructor(\n    private methodpoolApiService: MethodpoolApiService,\n    private galleryService: GalleryService,\n    element: Element,\n  ) {\n    this.domElement = element as HTMLElement;\n  }\n\n  private blockChanged(): void {\n    if(!this.block?.text) return;\n    const categories = MethodpoolUtils.parseRfgText(this.block.text);\n    this.categoryOne = categories[0];\n    this.categoryTwo = categories[1];\n    this.updateEntries(this.categoryOne);\n    this.updateEntries(this.categoryTwo);\n  }\n\n  private handleSaveBlock(): void {\n    assertNotNullOrUndefined(this.block, 'block cannot be null or undefined');\n    const categoryOne = this.categoryOne.trim();\n    const categoryTwo = this.categoryTwo.trim();\n    if(!this.checkCategoriesValid(categoryOne, categoryTwo)) return;\n    this.block.text = `${categoryOne};${categoryTwo}`;\n    DomUtils.fireEvent(this.domElement, {\n      name: 'edit-rfg-ok',\n      bubbles: false,\n    });\n  }\n\n  private handleCancelSaveBlock(): void {\n    DomUtils.fireEvent(this.domElement, {\n      name: 'edit-rfg-cancel',\n      bubbles: false,\n    });\n  }\n\n  private async updateEntries(category: string): Promise<void> {\n    if(!this.categoryValid(category)) return;\n    assertNotNullOrUndefined(this.courseId, 'courseId cannot be null or undefined');\n\n    try {\n      const entries = await this.methodpoolApiService.getRfgEntries(this.courseId, category);\n      if(category === this.categoryOne) {\n        this.categoryOneEntries = entries;\n      } else if(category === this.categoryTwo) {\n        this.categoryTwoEntries = entries;\n      }\n    } catch(e) {\n      LogUtils.exception(e);\n    }\n  }\n\n  private async addEntry(category: string, pictureId: number): Promise<void> {\n    assertNotNullOrUndefined(this.courseId, 'courseId cannot be null or undefined');\n    try {\n      await this.methodpoolApiService.createRfgEntry(this.courseId, category.trim(), pictureId);\n      await this.updateEntries(category);\n    } catch(e) {\n      LogUtils.exception(e);\n    }\n  }\n\n  private async removeRfgEntry(entryId: number, category: string): Promise<void> {\n    try {\n      await this.methodpoolApiService.removeRfgEntry(entryId);\n      await this.updateEntries(category);\n    } catch(e) {\n      LogUtils.exception(e);\n    }\n  }\n\n  private async removeAllEntries(entries: Array<IMpRapidfireEntryDto>, category: string): Promise<void> {\n    try {\n      for(const entry of entries) {\n        await this.methodpoolApiService.removeRfgEntry(entry.id);\n      }\n      await this.updateEntries(category);\n    } catch(e) {\n      LogUtils.exception(e);\n    }\n  }\n\n  private handleKeyPress(event: KeyboardEvent, category: string): boolean {\n    this.errorTk = null;\n    this.updateEntries(category);\n\n    if(event.key === KeyboardKey.Enter) {\n      return false;\n    }\n    return true;\n  }\n\n  private handleFileUploadSuccess = async (event: FileDropZoneUploadSuccessEvent<PictureUploadResponse>, category: string): Promise<void> => {\n    if(event.detail.response.success) {\n      this.errorTk = null;\n      const mediaType = this.galleryService.getMediaTypeForFile(event.detail.file);\n      assertNotNullOrUndefined(mediaType, 'expected uploaded file to have whitelisted media type');\n      const pictureId = event.detail.response.mediaId;\n      await this.addEntry(category, pictureId);\n    }\n  };\n\n  private uploadCallback = (file: File): Record<string, string> => {\n    const defaultUploadParams = this.galleryService.getDefaultUploadCallbackParams(file);\n    assertNotNullOrUndefined(this.courseId, 'courseId cannot be null or undefined');\n    return {\n      ...defaultUploadParams,\n      courseId: `${this.courseId}`\n    };\n  };\n\n  private uploadErrorCallback = (error: ApiError): void => {\n    this.galleryService.handleUploadError(error);\n  };\n\n  private addedFileCallback = (file: File): string | null => {\n    return this.uploadUrl;\n  };\n\n  private checkCategoriesValid(categoryOne: string, categoryTwo: string): boolean {\n    this.errorTk = ArrayUtils.getFirstNonNullValue(\n      (!this.categoryValid(categoryOne) || !this.categoryValid(categoryTwo) ? 'elements.mpRfgForm.categoriesEmptyError' : null),\n      (this.errorTk = categoryOne === categoryTwo ? 'elements.mpRfgForm.categoriesIdenticalError' : null),\n      (this.errorTk = !this.categoryOneEntries.length || !this.categoryTwoEntries.length ? 'elements.mpRfgForm.entriesEmptyError' : null),\n    );\n    return !this.errorTk;\n  }\n\n  private categoryValid(category: string): boolean {\n    return category.length > 0;\n  }\n}\n\nexport type EditRfgOkEvent = CustomEvent<never>;\nexport type EditRfgCancelEvent = CustomEvent<never>;\n","import { autoinject, bindable } from 'aurelia-framework';\nimport { I18N } from 'aurelia-i18n';\nimport { IMpRapidFireGameEntry } from 'common/aurelia-components/methodpool/mp-rapid-fire-game/mp-rapid-fire-game';\nimport { LogUtils } from 'common/utils/LogUtils';\nimport { MethodpoolUtils } from 'common/utils/MethodpoolUtils';\nimport { MethodpoolApiService } from '../../../services/api/MethodpoolApiService';\n\n@autoinject\nexport class MpRfgPreview {\n  @bindable public text: string = '';\n  @bindable public courseId: number | null = null;\n  private error: string | null = null;\n  private gameData: Array<IMpRapidFireGameEntry> = [];\n\n  constructor(private i18n: I18N, private methodpoolApiService: MethodpoolApiService) { }\n\n  private textChanged(): void {\n    this.reloadGameData();\n  }\n\n  private courseIdChanged(): void {\n    this.reloadGameData();\n  }\n\n  private async reloadGameData(): Promise<void> {\n    if(!this.courseId || !this.text) return;\n    this.error = null;\n    try {\n      const categories = MethodpoolUtils.parseRfgText(this.text);\n      if(categories.length < 2) throw new MpRfgPreviewError('elements.mpRfgPreview.lessThanTwoCategories');\n      let newGameData: Array<IMpRapidFireGameEntry> = [];\n      for(const category of categories) {\n        const entries = await this.methodpoolApiService.getRfgEntries(this.courseId, category);\n        if(entries.length === 0) throw new MpRfgPreviewError('elements.mpRfgPreview.categoryHasNoEntries', { category });\n        newGameData = newGameData.concat(entries.map(e => ({ category, text: e.text, picture: e.picture })));\n      }\n      this.gameData = newGameData;\n    } catch(e) {\n      if(e instanceof MpRfgPreviewError) {\n        this.error = this.i18n.tr(e.tk, e.params);\n      } else {\n        this.error = e;\n      }\n      LogUtils.exception(e);\n      this.gameData = [];\n    }\n  }\n\n}\n\nclass MpRfgPreviewError extends Error {\n  constructor(public tk: string, public params?: Record<string, string>) {\n    super('MpRfgPreviewError');\n    /** @see https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work */\n    Object.setPrototypeOf(this, MpRfgPreviewError.prototype);\n  }\n}\n","import { autoinject, bindable } from 'aurelia-framework';\nimport { BlockType } from 'common/dto/course/content/course.types';\nimport { ERisiLevel } from 'common/enum/risi.level.enum';\nimport { DomUtils } from 'common/utils/DomUtils';\nimport { IContentEditorBlockEditorBlock } from '../../dialogs/content-editor-block-editor-dialog/content-editor-block-editor-dialog';\n\n/**\n * @event {EditOkEvent} edit-ok\n * @event {EditCancelEvent} edit-cancel\n */\n@autoinject()\nexport class MpRisiForm {\n  @bindable() public blockId: number | null = null;\n  @bindable() public block: IContentEditorBlockEditorBlock | null = null;\n\n  private levelOptions: ERisiLevel[] = Object.values(ERisiLevel);\n  private selectedLevelOption: ERisiLevel = this.levelOptions[0];\n\n  private BlockType = BlockType;\n  private domElement: HTMLElement;\n\n  constructor(\n    element: Element,\n  ) {\n    this.domElement = element as HTMLElement;\n  }\n\n  private blockChanged(): void {\n    this.selectedLevelOption = this.levelOptions.find(l => this.block?.text === l) ?? this.levelOptions[0];\n  }\n\n  private handleSaveClick(): void {\n    if(this.block) {\n      this.block.text = this.selectedLevelOption;\n    }\n\n    DomUtils.fireEvent(this.domElement, {\n      name: 'edit-ok',\n      bubbles: false,\n    });\n  }\n\n  private handleCancelClick(): void {\n    DomUtils.fireEvent(this.domElement, {\n      name: 'edit-cancel',\n      bubbles: false,\n    });\n  }\n}\n\nexport type EditOkEvent = CustomEvent<never>;\nexport type EditCancelEvent = CustomEvent<never>;\n","import { autoinject, bindable } from 'aurelia-framework';\nimport { IMpTileDto } from 'common/dto/course/content/block.interface';\nimport { MethodpoolUtils } from 'common/utils/MethodpoolUtils';\nimport { CustomDialogService } from '../../../services/CustomDialogService';\n\n@autoinject()\nexport class MpTileForm {\n  @bindable() public tilesAsText: string = '';\n  @bindable() public tiles: Array<IMpTileDto> = [];\n\n  constructor(private customDialogService: CustomDialogService) { }\n\n  private async handleEditTile(tile: IMpTileDto, index: number): Promise<void> {\n    const tileInfo = MethodpoolUtils.parseTileText(this.tilesAsText)[index];\n    const result = await this.customDialogService.showEditTileDialog(tile, tileInfo);\n    if(result) {\n      this.tiles = [\n        ...this.tiles.slice(0, index),\n        result.tile,\n        ...this.tiles.slice(index + 1),\n      ];\n\n      const tileInfos = MethodpoolUtils.parseTileText(this.tilesAsText);\n      const updatedTileInfos = [\n        ...tileInfos.slice(0, index),\n        result.tileInfo,\n        ...tileInfos.slice(index + 1),\n      ];\n\n      this.tilesAsText = MethodpoolUtils.stringifyTileInfos(updatedTileInfos);\n    }\n  }\n\n  private handleDeleteTile(index: number): void {\n    this.tiles = this.tiles.filter((_, i) => i !== index);\n    let tileInfos = MethodpoolUtils.parseTileText(this.tilesAsText);\n    tileInfos = tileInfos.filter((_, i) => i !== index);\n    this.tilesAsText = MethodpoolUtils.stringifyTileInfos(tileInfos);\n  }\n\n  private async handleAddTile(): Promise<void> {\n    const result = await this.customDialogService.showEditTileDialog({}, {});\n\n    if(result) {\n      this.tiles = [...this.tiles, result.tile];\n      let tileInfos = this.tilesAsText.length ? MethodpoolUtils.parseTileText(this.tilesAsText) : [];\n      tileInfos = [...tileInfos, result.tileInfo];\n      this.tilesAsText = MethodpoolUtils.stringifyTileInfos(tileInfos);\n    }\n  }\n}\n","import arrow from '@popperjs/core/lib/modifiers/arrow';\nimport offset from '@popperjs/core/lib/modifiers/offset';\nimport { createPopper, Instance } from '@popperjs/core/lib/popper-lite';\nimport { autoinject, bindable, observable } from 'aurelia-framework';\nimport { I18N } from 'aurelia-i18n';\nimport { IdGeneratorService } from 'common/aurelia-services/IdGeneratorService';\nimport { SubscriptionManager, SubscriptionManagerService } from 'common/aurelia-services/SubscriptionManagerService';\nimport { KeyboardKey } from 'common/enum/keyboard.key.enum';\nimport { ArrayUtils } from 'common/utils/ArrayUtils';\nimport { assertNotNullOrUndefined } from 'common/utils/assert';\nimport { DomUtils } from 'common/utils/DomUtils';\n\n/**\n * @event {MultiSelectComboBoxSelectedItemChangedEvent} selected-items-changed\n */\n@autoinject()\nexport class MultiSelectComboBox<T extends Record<string, any>> {\n  @bindable() public show = false;\n  @bindable() public selectedItems: T[] = [];\n  @bindable() public totalItems: T[] = [];\n  @bindable() public labelPropertyName: keyof T | null = null;\n  @bindable() public isInvalid: boolean = false;\n  @bindable() public disabled: boolean = false;\n  @observable() public searchString = '';\n\n  public buttonRef!: HTMLElement;\n  public dropdownRef!: HTMLElement;\n\n  private subscriptionManager: SubscriptionManager;\n  private matchingItems: T[] = [];\n  private unmatchingItems: T[] = [];\n  private selectedMatchingItems: T[] = [];\n  private popper?: Instance;\n  private element: HTMLElement;\n  private id: string;\n  private placeholder = '';\n\n  constructor(\n    idGenerator: IdGeneratorService,\n    element: Element,\n    subscriptionManagerService: SubscriptionManagerService,\n    private i18n: I18N,\n  ) {\n    this.element = element as HTMLElement;\n    this.subscriptionManager = subscriptionManagerService.createSubscriptionManager();\n    this.element = element as HTMLElement;\n    this.id = idGenerator.getId().toString();\n  }\n\n  protected attached(): void {\n    this.updateItemsFound();\n    this.updatePlaceholder();\n    this.subscriptionManager.subscribeToDomEvent(window, 'keyup', () => this.handleKeyUp());\n    this.subscriptionManager.subscribeToClickOutside(this.element, () => {\n      this.hideMenu();\n    }, true);\n    this.subscriptionManager.subscribeToKeyboardEvent(window, KeyboardKey.Escape, () => {\n      this.hideMenu();\n    });\n  }\n\n  protected detached(): void {\n    this.popper?.destroy();\n    this.subscriptionManager.disposeSubscriptions();\n  }\n\n  private showMenu(): void {\n    this.show = true;\n    if(!this.popper) {\n      this.initPopper();\n    }\n    assertNotNullOrUndefined(this.popper, 'popper not ready');\n    this.popper.forceUpdate();\n  }\n\n  private hideMenu(): void {\n    this.show = false;\n  }\n\n  private initPopper(): void {\n    this.popper = createPopper(this.buttonRef, this.dropdownRef, {\n      placement: 'bottom-start',\n      strategy: 'fixed',\n      modifiers: [\n        arrow,\n        offset,\n        {\n          name: 'offset',\n          options: {\n            offset: [0, 0],\n          },\n        },\n      ],\n    });\n  }\n\n  private updateItemsFound(): void {\n    if(this.totalItems) {\n      this.searchString = '';\n      this.matchingItems = [...this.totalItems];\n      this.unmatchingItems = [];\n    }\n  }\n\n  private updatePlaceholder(): void {\n    if(this.selectedItems && this.selectedItems.length === 0) {\n      this.placeholder = this.i18n.tr('globals.select');\n    } else {\n      this.placeholder = this.selectedItems.map(item => this.labelPropertyName && item[this.labelPropertyName]).join(', ');\n    }\n  }\n\n  private searchItems(searchString: string): void {\n    const lowerCaseSearchString = searchString.toLowerCase();\n    const { matched, unmatched } = ArrayUtils.groupBy(\n      this.totalItems,\n      item => this.labelPropertyName && item[this.labelPropertyName].toLowerCase().includes(lowerCaseSearchString)\n        ? 'matched'\n        : 'unmatched'\n    );\n\n    this.matchingItems = matched ?? [];\n    this.unmatchingItems = unmatched ?? [];\n\n    const matchingItemsSet = new Set(this.matchingItems);\n    this.selectedMatchingItems = this.selectedItems.filter(si => matchingItemsSet.has(si));\n  }\n\n  private selectAllItems(): void {\n    const allAlreadySelected = this.selectedItems.length === this.totalItems.length;\n    ArrayUtils.filterInPlace(this.selectedItems, () => false);\n    if(!allAlreadySelected) this.selectedItems.push(...this.totalItems);\n\n    this.handleSelectedItemsChanged();\n  }\n\n  private selectAllMatchingItems(): void {\n    const allAlreadySelected = this.selectedMatchingItems.length === this.matchingItems.length;\n    const matchingItemsSet = new Set(this.matchingItems);\n    ArrayUtils.filterInPlace(this.selectedItems, si => !matchingItemsSet.has(si));\n    if(!allAlreadySelected) this.selectedItems.push(...this.matchingItems);\n\n    this.handleSelectedItemsChanged();\n  }\n\n  private handleSelectedItemsChanged(): void {\n    const matchingItemsSet = new Set(this.matchingItems);\n    this.selectedMatchingItems = this.selectedItems.filter(si => matchingItemsSet.has(si));\n    this.updatePlaceholder();\n\n    DomUtils.fireEvent(this.element, {\n      bubbles: true,\n      detail: { selectedItems: this.selectedItems },\n      name: 'selected-items-changed',\n    });\n  }\n\n  private searchStringChanged(filter: string): void {\n    if(filter !== '') {\n      this.searchItems(filter);\n    } else {\n      this.updateItemsFound();\n    }\n  }\n\n  private showChanged(): void {\n    if(!this.show) this.searchString = '';\n  }\n\n  private totalItemsChanged(): void {\n    this.updateItemsFound();\n    this.updatePlaceholder();\n  }\n\n  private labelPropertyNameChanged(): void {\n    this.updatePlaceholder();\n  }\n\n  private selectedItemsChanged(): void {\n    this.updateItemsFound();\n    this.updatePlaceholder();\n  }\n\n  private handleKeyUp(): void {\n    if(!this.element.contains(document.activeElement)) {\n      this.hideMenu();\n    }\n  }\n}\n\nexport type MultiSelectComboBoxSelectedItemChangedEvent<T> = Event & { detail: { selectedItems: T[] } };\n","import { IState } from '../../../../store/state';\nimport { INavigationSubMenu } from '../navigation-bar';\nimport { INavigationMenuEntry } from '../navigation-bar-menu';\n\nexport enum NavigationMenuEntryRouteName {\n  ANNOUNCEMENTS = 'announcements',\n  ASSESSMENTS = 'assessments',\n  AVATAR_COMPONENTS = 'avatar-component-sets',\n  BILLING_EXPORT = 'billing-csv-export',\n  BLOCK_LIST = 'blocklist',\n  COURSE_GROUPS = 'tenant-group-list',\n  COURSES = 'courses',\n  EVENTS = 'events',\n  HOME = 'home',\n  LEARNING_JOURNEYS = 'learning-journeys',\n  LECTURER_EVENTS = 'lecturer-events',\n  LOGS = 'logs',\n  MEDIA_GALLERY = 'gallery',\n  MEDIA_SHARES = 'media-share',\n  PAGE_HELP = 'page-help',\n  PRESENTATION_OVERVIEW = 'presentation-overview',\n  PRESENTATION_VIEWER = 'presentations/id',\n  QUIZ_TEMPLATES = 'quiz-templates',\n  SKILL_MATRIX = 'skill-matrix',\n  SKILLS = 'skills',\n  STAFF = 'administrative-staff',\n  STATISTICS_ACCESS_CODES = 'statistics-access-codes',\n  STATISTICS_ASSESSMENTS = 'statistics-assessments',\n  STATISTICS_COURSE_PROGRESS = 'statistics-course-progress',\n  STATISTICS_EVENTS = 'statistics-events',\n  STATISTICS_TESTEXAMS = 'statistics-testexam',\n  STUDENTS = 'tenant-student-list',\n  SYNC_API = 'external-api',\n  TEACHER_REGISTRATIONS = 'teacher-registrations',\n  TENANTS = 'tenants',\n  USER_ADMINISTRATION = 'user-administration',\n}\n\nexport const accessCodesStatsMenuEntry: INavigationMenuEntry = {\n  tk: 'navigation.accessCodesStats',\n  icon: 'fe-square',\n  routeName: NavigationMenuEntryRouteName.STATISTICS_ACCESS_CODES,\n};\n\nexport const announcementsMenuEntry: INavigationMenuEntry = {\n  tk: 'navigation.announcements',\n  icon: 'fe-alert-octagon',\n  routeName: NavigationMenuEntryRouteName.ANNOUNCEMENTS,\n};\n\nexport const assessmentStatsMenuEntry: INavigationMenuEntry = {\n  tk: 'navigation.assessmentsStats',\n  icon: 'LectureQuiz/Quiz',\n  customIcon: true,\n  routeName: NavigationMenuEntryRouteName.STATISTICS_ASSESSMENTS,\n};\n\nexport const assessmentsMenuEntry: INavigationMenuEntry = {\n  tk: 'navigation.assessments',\n  icon: 'System/Tabler/File',\n  customIcon: true,\n  routeName: NavigationMenuEntryRouteName.ASSESSMENTS,\n};\n\nexport const blockListMenuEntry: INavigationMenuEntry = {\n  tk: 'navigation.blocklist',\n  icon: 'fe-alert-circle',\n  routeName: NavigationMenuEntryRouteName.BLOCK_LIST,\n};\n\nexport const courseProgressStatsMenuEntry: INavigationMenuEntry = {\n  tk: 'navigation.courseProgressStatistics',\n  icon: 'fe-square',\n  routeName: NavigationMenuEntryRouteName.STATISTICS_COURSE_PROGRESS,\n};\n\nexport const coursesMenuEntry: INavigationSubMenu = {\n  tk: 'navigation.courses',\n  icon: 'System/Tabler/List',\n  customIcon: true,\n  subMenu: [\n    {\n      tk: 'navigation.management',\n      icon: 'System/Tabler/List',\n      customIcon: true,\n      routeName: NavigationMenuEntryRouteName.COURSES\n    },\n    {\n      tk: 'navigation.avatarComponentSets',\n      icon: 'System/Tabler/User-Circle',\n      customIcon: true,\n      routeName: NavigationMenuEntryRouteName.AVATAR_COMPONENTS\n    },\n  ],\n};\n\nexport const eventStatsMenuEntry: INavigationMenuEntry = {\n  tk: 'navigation.eventStats',\n  icon: 'System/Tabler/Calendar-Time',\n  customIcon: true,\n  routeName: NavigationMenuEntryRouteName.STATISTICS_EVENTS,\n};\n\nexport const homeMenuEntry: INavigationMenuEntry = {\n  tk: 'navigation.home',\n  icon: 'System/Tabler/Home',\n  customIcon: true,\n  routeName: NavigationMenuEntryRouteName.HOME,\n};\n\nexport const billingExportMenuEntry: INavigationMenuEntry = {\n  tk: 'navigation.csv-export',\n  icon: 'fe-printer',\n  routeName: NavigationMenuEntryRouteName.BILLING_EXPORT,\n};\n\nexport const learningJourneyMenuEntry: INavigationSubMenu = {\n  tk: 'navigation.learningJourneys',\n  icon: 'System/Tabler/Route',\n  customIcon: true,\n  subMenu: [\n    {\n      tk: 'navigation.learningJourneys',\n      icon: 'System/Tabler/Route',\n      customIcon: true,\n      routeName: NavigationMenuEntryRouteName.LEARNING_JOURNEYS,\n    },\n    {\n      tk: 'navigation.skills',\n      icon: 'System/Tabler/Rocket',\n      customIcon: true,\n      routeName: NavigationMenuEntryRouteName.SKILLS,\n    },\n    {\n      tk: 'navigation.skillMatrix',\n      icon: 'System/Tabler/Grid-Dots',\n      customIcon: true,\n      routeName: NavigationMenuEntryRouteName.SKILL_MATRIX,\n    },\n  ],\n};\n\nexport const logMenuEntry: INavigationMenuEntry = {\n  tk: 'navigation.logs',\n  icon: 'System/Tabler/List',\n  customIcon: true,\n  routeName: NavigationMenuEntryRouteName.LOGS,\n};\n\nexport const mediaGalleryMenuEntry: INavigationMenuEntry = {\n  tk: 'navigation.gallery',\n  icon: 'fe-grid',\n  routeName: NavigationMenuEntryRouteName.MEDIA_GALLERY,\n};\n\nexport const mediaShareMenuEntry: INavigationMenuEntry = {\n  tk: 'navigation.mediashare',\n  icon: 'fe-share',\n  routeName: NavigationMenuEntryRouteName.MEDIA_SHARES,\n};\n\nexport const pageHelpMenuEntry: INavigationMenuEntry = {\n  tk: 'navigation.pageHelp',\n  icon: 'fe-help-circle',\n  routeName: NavigationMenuEntryRouteName.PAGE_HELP,\n};\n\nexport const presentationEditorMenuEntry: INavigationMenuEntry = {\n  tk: 'navigation.presentationBuilder',\n  icon: 'System/Tabler/Presentation - Analytics',\n  customIcon: true,\n  routeName: NavigationMenuEntryRouteName.PRESENTATION_OVERVIEW,\n};\n\nexport const presentationViewerMenuEntry: INavigationMenuEntry = {\n  tk: 'navigation.presentationSlides',\n  icon: 'fe-sidebar',\n  routeName: NavigationMenuEntryRouteName.PRESENTATION_VIEWER,\n};\n\nexport const providerStaffMenuEntry: INavigationMenuEntry = {\n  tk: 'navigation.administrativeStaff',\n  icon: 'System/Tabler/User-Star',\n  customIcon: true,\n  routeName: NavigationMenuEntryRouteName.STAFF,\n};\n\nexport const providerStudentMenuEntry: INavigationMenuEntry = {\n  tk: 'navigation.students',\n  icon: 'System/Tabler/Users',\n  customIcon: true,\n  routeName: NavigationMenuEntryRouteName.STUDENTS,\n};\n\nexport const quizMenuEntry: INavigationMenuEntry = {\n  tk: 'navigation.quiz',\n  icon: 'LectureQuiz/Quiz',\n  customIcon: true,\n  routeName: NavigationMenuEntryRouteName.QUIZ_TEMPLATES,\n};\n\nexport const studentMenuEntry: INavigationSubMenu = {\n  tk: 'navigation.students',\n  icon: 'System/Tabler/Users',\n  customIcon: true,\n  subMenu: [\n    {\n      tk: 'navigation.management',\n      icon: 'System/Tabler/Users',\n      customIcon: true,\n      routeName: NavigationMenuEntryRouteName.STUDENTS,\n    },\n    {\n      tk: 'navigation.groups',\n      icon: 'System/Tabler/Users',\n      customIcon: true,\n      routeName: NavigationMenuEntryRouteName.COURSE_GROUPS,\n    },\n  ],\n};\n\nexport const syncApiMenuEntry: INavigationMenuEntry = {\n  tk: 'navigation.api',\n  icon: 'fe-repeat',\n  routeName: NavigationMenuEntryRouteName.SYNC_API,\n};\n\nexport const teacherRegistrationsMenuEntry: INavigationMenuEntry = {\n  tk: 'navigation.teacherRegistrations',\n  icon: 'System/Tabler/Folder',\n  customIcon: true,\n  routeName: NavigationMenuEntryRouteName.TEACHER_REGISTRATIONS,\n  countableStateExtractor: (state: IState): number => state.pendingTeacherRegistrationsCount\n};\n\nexport const tenantMenuEntry: INavigationMenuEntry = {\n  tk: 'navigation.tenants',\n  icon: 'System/Tabler/Building-Bank',\n  customIcon: true,\n  routeName: NavigationMenuEntryRouteName.TENANTS,\n};\n\nexport const testExamStatsMenuEntry: INavigationMenuEntry = {\n  tk: 'navigation.testexamStats',\n  icon: 'LectureQuiz/Quiz',\n  customIcon: true,\n  routeName: NavigationMenuEntryRouteName.STATISTICS_TESTEXAMS,\n};\n\nexport const userAdministrationMenuEntry: INavigationMenuEntry = {\n  tk: 'navigation.user-administration',\n  icon: 'System/Tabler/Users',\n  customIcon: true,\n  routeName: NavigationMenuEntryRouteName.USER_ADMINISTRATION,\n};\n\nconst surveyLink = 'https://r.kfv.at/RFP_Umfrage';\nexport const surveyMenuEntry: INavigationMenuEntry = {\n  tk: 'navigation.survey',\n  icon: 'System/Tabler/External-Link',\n  customIcon: true,\n  externalLink: surveyLink,\n};\n","import { AppUtils } from 'common/utils/AppUtils';\nimport { assessmentsMenuEntry, homeMenuEntry, NavigationMenuEntryRouteName, surveyMenuEntry } from '../menu-entries';\nimport { INavigationSubMenu } from '../navigation-bar';\nimport { INavigationMenuEntry } from '../navigation-bar-menu';\nimport { teachingMaterialMenuEntry } from './teaching-material-menu-entry';\n\nexport const lecturerMenuEntries: Array<INavigationMenuEntry | INavigationSubMenu> = AppUtils.isFrp ? [\n  homeMenuEntry,\n  assessmentsMenuEntry,\n  surveyMenuEntry,\n] : [\n  homeMenuEntry,\n  {\n    tk: 'navigation.student-administration',\n    icon: 'System/Tabler/Users',\n    customIcon: true,\n    routeName: 'tenant-student-list',\n  },\n  {\n    ...teachingMaterialMenuEntry,\n    subMenu: [\n      ...teachingMaterialMenuEntry.subMenu,\n      {\n        tk: 'navigation.courseGroupMediaShares',\n        icon: 'fe-share',\n        routeName: 'media-share',\n      },\n    ]\n  },\n  {\n    tk: 'navigation.myEvents',\n    icon: 'System/Tabler/Calendar-Time',\n    customIcon: true,\n    routeName: NavigationMenuEntryRouteName.LECTURER_EVENTS,\n  },\n  {\n    tk: 'navigation.messages',\n    icon: 'fe-message-circle',\n    routeName: 'messages/id'\n  },\n];\n","import { Config } from 'common/fe-config/config';\nimport { AppUtils } from 'common/utils/AppUtils';\nimport { \n  NavigationMenuEntryRouteName,\n  homeMenuEntry,\n  learningJourneyMenuEntry,\n  teacherRegistrationsMenuEntry,\n  studentMenuEntry,\n  userAdministrationMenuEntry,\n  billingExportMenuEntry,\n} from '../menu-entries';\nimport { INavigationSubMenu } from '../navigation-bar';\nimport { INavigationMenuEntry } from '../navigation-bar-menu';\nimport { teachingMaterialMenuEntry } from './teaching-material-menu-entry';\n\nexport const operatorMenuEntries: Array<INavigationMenuEntry | INavigationSubMenu> = AppUtils.isFrp ? [\n  homeMenuEntry,\n  userAdministrationMenuEntry,\n  teacherRegistrationsMenuEntry\n] : [\n  homeMenuEntry,\n  studentMenuEntry,\n  ...Config().learningJourney.enabled ? [learningJourneyMenuEntry] : [],\n  {\n    ...teachingMaterialMenuEntry,\n    subMenu: [\n      {\n        tk: 'navigation.courseManagement',\n        icon: 'System/Tabler/List',\n        customIcon: true,\n        routeName: 'tenant-courses'\n      },\n      ...teachingMaterialMenuEntry.subMenu,\n      {\n        tk: 'navigation.courseGroupMediaShares',\n        icon: 'fe-share',\n        routeName: 'media-share',\n      },\n    ]\n  },\n  {\n    tk: 'navigation.events',\n    icon: 'System/Tabler/Calendar-Empty',\n    customIcon: true,\n    subMenu: [\n      {\n        tk: 'navigation.events',\n        icon: 'System/Tabler/Calendar-Empty',\n        customIcon: true,\n        routeName: NavigationMenuEntryRouteName.EVENTS\n      },\n      {\n        tk: 'navigation.myEvents',\n        icon: 'System/Tabler/Calendar-Time',\n        customIcon: true,\n        routeName: NavigationMenuEntryRouteName.LECTURER_EVENTS\n      },\n    ],\n  },\n  {\n    tk: 'navigation.messages',\n    icon: 'fe-message-circle',\n    routeName: 'messages/id'\n  },\n  {\n    tk: 'navigation.administration',\n    icon: 'System/Tabler/Settings',\n    customIcon: true,\n    subMenu: [\n      {\n        tk: 'navigation.employees',\n        icon: 'System/Tabler/User-Star',\n        customIcon: true,\n        routeName: 'employees'\n      },\n      {\n        tk: 'navigation.addresses',\n        icon: 'fe-map-pin',\n        routeName: 'addresses'\n      },\n      billingExportMenuEntry,\n      {\n        tk: 'navigation.announcements',\n        icon: 'fe-alert-octagon',\n        routeName: 'announcements',\n      },\n      ...Config().syncApi.enabled ? [{\n        tk: 'navigation.api',\n        icon: 'fe-repeat',\n        routeName: 'external-api'\n      }] : [],\n    ],\n  },\n  ...Config().statistics.enabled ? [\n    {\n      tk: 'navigation.stats',\n      icon: 'System/Tabler/Chart-Info',\n      customIcon: true,\n      subMenu: [\n        {\n          tk: 'navigation.eventStats',\n          icon: 'System/Tabler/Calendar-Time',\n          customIcon: true,\n          routeName: NavigationMenuEntryRouteName.STATISTICS_EVENTS,\n        },\n        {\n          tk: 'navigation.testexamStats',\n          icon: 'LectureQuiz/Quiz',\n          customIcon: true,\n          routeName: 'statistics-testexam',\n        },\n      ],\n    },\n  ] : [],\n  {\n    tk: 'navigation.logs',\n    icon: 'System/Tabler/List',\n    customIcon: true,\n    routeName: 'logs'\n  },\n];\n","import { Config } from 'common/fe-config/config';\nimport { INavigationSubMenu } from '../navigation-bar';\nimport { INavigationMenuEntry } from '../navigation-bar-menu';\nimport { teachingMaterialMenuEntry } from './teaching-material-menu-entry';\nimport { NavigationMenuEntryRouteName, homeMenuEntry, teacherRegistrationsMenuEntry, studentMenuEntry, userAdministrationMenuEntry } from '../menu-entries';\nimport { AppUtils } from 'common/utils/AppUtils';\n\nexport const poweruserMenuEntries: Array<INavigationMenuEntry | INavigationSubMenu> = AppUtils.isFrp ? [\n  homeMenuEntry,\n  userAdministrationMenuEntry,\n  teacherRegistrationsMenuEntry\n] : [\n  homeMenuEntry,\n  studentMenuEntry,\n  {\n    ...teachingMaterialMenuEntry,\n    subMenu: [\n      ...teachingMaterialMenuEntry.subMenu,\n      {\n        tk: 'navigation.courseGroupMediaShares',\n        icon: 'fe-share',\n        routeName: 'media-share',\n      },\n    ]\n  },\n  {\n    tk: 'navigation.events',\n    icon: 'System/Tabler/Calendar-Empty',\n    customIcon: true,\n    subMenu: [\n      {\n        tk: 'navigation.events',\n        icon: 'System/Tabler/Calendar-Empty',\n        customIcon: true,\n        routeName: NavigationMenuEntryRouteName.EVENTS,\n      },\n      {\n        tk: 'navigation.myEvents',\n        icon: 'System/Tabler/Calendar-Time',\n        customIcon: true,\n        routeName: NavigationMenuEntryRouteName.LECTURER_EVENTS,\n      },\n    ],\n  },\n  {\n    tk: 'navigation.messages',\n    icon: 'fe-message-circle',\n    routeName: 'messages/id'\n  },\n  ...Config().syncApi.enabled ? [{\n    tk: 'navigation.administration',\n    icon: 'System/Tabler/Settings',\n    customIcon: true,\n    subMenu: [\n      {\n        tk: 'navigation.api',\n        icon: 'fe-repeat',\n        routeName: 'external-api'\n      },\n    ],\n  }] : [],\n];\n","import { Config } from 'common/fe-config/config';\nimport { AppUtils } from 'common/utils/AppUtils';\nimport {\n  accessCodesStatsMenuEntry,\n  announcementsMenuEntry,\n  assessmentStatsMenuEntry,\n  billingExportMenuEntry,\n  blockListMenuEntry,\n  courseProgressStatsMenuEntry,\n  coursesMenuEntry,\n  eventStatsMenuEntry,\n  homeMenuEntry,\n  logMenuEntry,\n  mediaGalleryMenuEntry,\n  mediaShareMenuEntry,\n  pageHelpMenuEntry,\n  presentationEditorMenuEntry,\n  presentationViewerMenuEntry,\n  providerStaffMenuEntry,\n  providerStudentMenuEntry,\n  syncApiMenuEntry,\n  tenantMenuEntry,\n  testExamStatsMenuEntry\n} from '../menu-entries';\nimport { INavigationSubMenu } from '../navigation-bar';\nimport { INavigationMenuEntry } from '../navigation-bar-menu';\nimport { teachingMaterialMenuEntry } from './teaching-material-menu-entry';\n\nexport const providerMenuEntries: Array<INavigationMenuEntry | INavigationSubMenu> = AppUtils.isFrp ? [\n  homeMenuEntry,\n  tenantMenuEntry,\n  coursesMenuEntry,\n  {\n    ...teachingMaterialMenuEntry,\n    subMenu: [\n      presentationViewerMenuEntry,\n      presentationEditorMenuEntry,\n      mediaGalleryMenuEntry,\n      mediaShareMenuEntry\n    ]\n  },\n  providerStaffMenuEntry,\n  {\n    tk: 'navigation.administration',\n    icon: 'System/Tabler/Settings',\n    customIcon: true,\n    subMenu: [\n      announcementsMenuEntry,\n      pageHelpMenuEntry,\n      ...Config().syncApi.enabled ? [syncApiMenuEntry] : [],\n    ],\n  },\n  ...Config().statistics.enabled ? [\n    {\n      tk: 'navigation.stats',\n      icon: 'System/Tabler/Chart-Info',\n      customIcon: true,\n      subMenu: [\n        testExamStatsMenuEntry,\n        assessmentStatsMenuEntry,\n        courseProgressStatsMenuEntry,\n        accessCodesStatsMenuEntry,\n      ],\n    },\n  ] : [],\n  logMenuEntry\n] : [\n  homeMenuEntry,\n  tenantMenuEntry,\n  coursesMenuEntry,\n  {\n    ...teachingMaterialMenuEntry,\n    subMenu: [\n      ...teachingMaterialMenuEntry.subMenu,\n      mediaShareMenuEntry\n    ]\n  },\n  {\n    tk: 'navigation.users',\n    icon: 'System/Tabler/Users',\n    customIcon: true,\n    subMenu: [\n      providerStudentMenuEntry,\n      providerStaffMenuEntry\n    ],\n  },\n  {\n    tk: 'navigation.administration',\n    icon: 'System/Tabler/Settings',\n    customIcon: true,\n    subMenu: [\n      billingExportMenuEntry,\n      blockListMenuEntry,\n      announcementsMenuEntry,\n      pageHelpMenuEntry,\n      ...Config().syncApi.enabled ? [syncApiMenuEntry] : [],\n    ],\n  },\n  ...Config().statistics.enabled ? [\n    {\n      tk: 'navigation.stats',\n      icon: 'System/Tabler/Chart-Info',\n      customIcon: true,\n      subMenu: [\n        eventStatsMenuEntry,\n        testExamStatsMenuEntry,\n        courseProgressStatsMenuEntry,\n        accessCodesStatsMenuEntry,\n      ],\n    },\n  ] : [],\n  logMenuEntry\n];\n","import { mediaGalleryMenuEntry, presentationEditorMenuEntry, presentationViewerMenuEntry, quizMenuEntry } from '../menu-entries';\nimport { INavigationSubMenu } from '../navigation-bar';\n\nexport const teachingMaterialMenuEntry: INavigationSubMenu = {\n  tk: 'navigation.teachingMaterial',\n  icon: 'System/Tabler/Notebook',\n  customIcon: true,\n  subMenu: [\n    quizMenuEntry,\n    presentationViewerMenuEntry,\n    presentationEditorMenuEntry,\n    mediaGalleryMenuEntry\n  ],\n};\n","import { autoinject, bindable } from 'aurelia-framework';\nimport { StoreService } from 'common/aurelia-services/StoreService';\nimport { IState } from '../../../store/state';\nimport { INavigationSubMenu } from './navigation-bar';\nimport { INavigationMenuEntry } from './navigation-bar-menu';\n\n@autoinject()\nexport class NavigationBarItem {\n  @bindable() public item: (INavigationMenuEntry | INavigationSubMenu) | null = null;\n  private itemCount: number = 0;\n\n  constructor(\n    private storeService: StoreService<IState>,\n  ) { }\n\n  protected attached(): void {\n    if(!this.item?.countableStateExtractor) return;\n    this.storeService.subscribeToDetailedChanges(this, [\n      state => this.item?.countableStateExtractor?.(state) ?? 0\n    ], (_state, itemCount) => {\n      this.itemCount = itemCount;\n    });\n  }\n\n  protected detached(): void {\n    this.storeService.disposeAllSubscriptions(this);\n  }\n}","import { autoinject, bindable, computedFrom } from 'aurelia-framework';\nimport { Router } from 'aurelia-router';\nimport { IState } from '../../../store/state';\nimport { NavigationMenuEntryRouteName } from './menu-entries';\n\n@autoinject()\nexport class NavigationBarMenu {\n  @bindable() public titleTk = '';\n  @bindable() public titleIcon: string | null = null;\n  @bindable() public isCustom: boolean = false;\n  @bindable() public entries: Array<INavigationMenuEntry> = [];\n\n  protected showMenu = false;\n\n  constructor(private router: Router) { }\n\n  @computedFrom('router.currentInstruction.config.name', 'entries')\n  public get isActive(): boolean {\n    return this.entries.some(e => e.routeName && this.router.currentInstruction.config.name?.startsWith(e.routeName) || false);\n  }\n\n  protected handleClick(): void {\n    this.showMenu = !this.showMenu;\n  }\n}\n\nexport interface INavigationMenuEntry {\n  tk: string;\n  icon?: string;\n  customIcon?: boolean;\n  routeName?: string | NavigationMenuEntryRouteName;\n  countableStateExtractor?: (state: IState) => number;\n  externalLink?: string;\n}\n","import { autoinject, bindable, computedFrom } from 'aurelia-framework';\nimport { IBreadcrumb } from 'common/aurelia-components/breadcrumbs/breadcrumbs';\nimport { StoreService } from 'common/aurelia-services/StoreService';\nimport { IRoleAssignment } from 'common/dto/auth/auth.interface';\nimport { RoleName } from 'common/enum/role.enums';\nimport { assertNotNullOrUndefined } from 'common/utils/assert';\nimport { BreadcrumbService } from '../../../services/BreadcrumbService';\nimport { IState } from '../../../store/state';\nimport { NavigationMenuEntryRouteName } from './menu-entries';\nimport { lecturerMenuEntries } from './menus/lecturer-menu';\nimport { operatorMenuEntries } from './menus/operator-menu';\nimport { poweruserMenuEntries } from './menus/poweruser-menu';\nimport { providerMenuEntries } from './menus/provider-menu';\nimport { INavigationMenuEntry } from './navigation-bar-menu';\n\nexport type INavigationSubMenu = Omit<INavigationMenuEntry, 'routeName'> & { subMenu: INavigationMenuEntry[] };\n\n@autoinject()\nexport class NavigationBar {\n  @bindable() public navBarVisible: boolean = false;\n  private breadcrumbs: Array<IBreadcrumb> = [];\n\n  private activeMenuEntries: (INavigationMenuEntry | INavigationSubMenu)[] = [];\n  private roles: Array<IRoleAssignment<string>> = [];\n  private showEvents: boolean = false;\n\n  constructor(\n    private storeService: StoreService<IState>,\n    private breadcrumbService: BreadcrumbService,\n  ) { }\n\n  protected attached(): void {\n    this.storeService.subscribeToDetailedChanges(this, [\n      state => state.roles,\n      state => state.currentRole?.role ?? null,\n      state => state.currentTenant,\n    ], (_, roles, currentRole, currentTenant) => {\n      this.roles = roles;\n      this.showEvents = !!currentTenant?.showEvents;\n      this.updateActiveMenuEntries(currentRole);\n    });\n\n    this.breadcrumbService.subscribeToBreadcrumbs(this, breadcrumbs => {\n      this.breadcrumbs = breadcrumbs;\n    });\n  }\n\n  protected detached(): void {\n    this.storeService.disposeAllSubscriptions(this);\n    this.breadcrumbService.disposeSubscriptions(this);\n  }\n\n  private updateActiveMenuEntries(currentRole: RoleName | null): void {\n    this.activeMenuEntries = [];\n    let entries: (INavigationMenuEntry | INavigationSubMenu)[] = [];\n    switch(currentRole) {\n      case RoleName.Provider:\n        this.activeMenuEntries = providerMenuEntries;\n        return;\n      case RoleName.Operator:\n        entries = operatorMenuEntries;\n        break;\n      case RoleName.PowerUser:\n        entries = poweruserMenuEntries;\n        break;\n      case RoleName.Lecturer:\n        entries = lecturerMenuEntries;\n        break;\n      default:\n        entries = [];\n        break;\n    }\n\n    if(!this.showEvents) {\n      const eventRoutes = [\n        NavigationMenuEntryRouteName.EVENTS,\n        NavigationMenuEntryRouteName.LECTURER_EVENTS,\n        NavigationMenuEntryRouteName.STATISTICS_EVENTS,\n        NavigationMenuEntryRouteName.QUIZ_TEMPLATES,\n        NavigationMenuEntryRouteName.PRESENTATION_OVERVIEW,\n        NavigationMenuEntryRouteName.PRESENTATION_VIEWER,\n      ];\n\n      const allowedEntries: (INavigationMenuEntry | INavigationSubMenu)[] = [];\n\n      for(const entry of entries) {\n        let cleanEntry = { ...entry };\n        // in operator isn't acting reliably in this case\n        const routeName = 'routeName' in entry ? (entry?.routeName ?? '') : '';\n        const subMenu = 'subMenu' in entry ? (entry?.subMenu ?? []) : [];\n\n        if(subMenu.length) {\n          // every sub entry is forbidden, remove the whole entry\n          if(subMenu.every(sE => eventRoutes.includes(sE.routeName as NavigationMenuEntryRouteName))) {\n            continue;\n          } else {\n            // some sub entries are forbidden, remove those\n            const cleanSubMenu = subMenu?.filter(sE => !eventRoutes.includes(sE.routeName as NavigationMenuEntryRouteName)) ?? [];\n            // sub menu hasn't any entries, remove the whole entry\n            if(!cleanSubMenu.length) {\n              continue;\n            }\n            cleanEntry = {\n              ...entry,\n              subMenu: cleanSubMenu\n            };\n          }\n          // the entry is forbidden, remove it\n        } else if(eventRoutes.includes(routeName as NavigationMenuEntryRouteName)) {\n          continue;\n        }\n        allowedEntries.push(cleanEntry);\n      }\n      entries = allowedEntries;\n    }\n\n    this.activeMenuEntries = entries;\n  }\n\n  @computedFrom('roles')\n  private get hasPendingRoles(): boolean {\n    assertNotNullOrUndefined(this.roles, 'roles cannot be null or undefined');\n    return this.roles.some(r => r.pending);\n  }\n\n  @computedFrom('breadcrumbs')\n  private get showBreadcrumbs(): boolean {\n    return this.breadcrumbs.length > 0;\n  }\n}\n","import { bindable } from 'aurelia-framework';\n\nexport class NavigationTabs {\n  @bindable() public tabs: INavigationTab[] = [];\n  @bindable() public wideTabs = false;\n  @bindable() public fillWidth = false;\n  @bindable() public fillHeight = false;\n  @bindable() public noBorder = false;\n  @bindable() public horizontalPadding = false;\n  @bindable() public disabled = false;\n\n  private handleTabSelected(selectedTab: INavigationTab): void {\n    for(const tab of this.tabs) {\n      tab.active = tab.active = tab === selectedTab;\n    }\n    selectedTab.callback();\n  }\n}\n\nexport interface INavigationTab {\n  title: INavigationTabTitle;\n  active: boolean;\n  callback: () => void;\n}\n\nexport interface INavigationTabTitle {\n  titleTk?: string;\n  titleText?: string;\n  titleTkParams?: Record<string, string | number>;\n}\n","import { FrameworkConfiguration, PLATFORM } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('resources/elements/notification-bell/notification-bell'));\n}\n","import { autoinject, computedFrom } from 'aurelia-framework';\nimport { Router } from 'aurelia-router';\nimport { StoreService, StoreSubscriptionManager } from 'common/aurelia-services/StoreService';\nimport { ICommonState } from 'common/store/store.interface';\nimport { selectHasUnreadChats } from 'common/store/selectors/selectors';\n\n@autoinject()\nexport class NotificationBell {\n  private storeSubscriptionManager: StoreSubscriptionManager<ICommonState>;\n  private indicateNewMessages = false;\n\n  constructor(\n    storeService: StoreService<ICommonState>,\n    private router: Router,\n  ) {\n    this.storeSubscriptionManager = storeService.createStoreSubscriptionManager();\n  }\n\n  protected attached(): void {\n    this.storeSubscriptionManager.subscribeToDetailedChanges([\n      selectHasUnreadChats,\n    ], (_, hasNewMessages) => {\n      this.indicateNewMessages = hasNewMessages;\n    });\n  }\n\n  protected detached(): void {\n    this.storeSubscriptionManager.unsubscribe();\n  }\n\n  @computedFrom('indicateNewMessages')\n  private get iconName(): string {\n    return this.indicateNewMessages\n      ? 'System/Notification - Incoming'\n      : 'System/Notification';\n  }\n\n  private goToMessages(): void {\n    this.router.navigateToRoute('messages/id');\n  }\n}\n","import { FrameworkConfiguration, PLATFORM } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('resources/elements/operation-status-list/operation-status-list-item/operation-status-list-item'));\n  config.globalResources(PLATFORM.moduleName('resources/elements/operation-status-list/operation-status-list'));\n}","import { autoinject, bindable, computedFrom } from 'aurelia-framework';\nimport { MediaImportReportFile, MediaImportWorkerReturnValue, OperationStatus } from 'common/dto/other/operation.response';\nimport { TrackedExportImportOperation, TrackedImportOperation, TrackedOperationType } from '../../../../services/ExportImportService';\n\n@autoinject()\nexport class OperationStatusListItem {\n  @bindable() public item: TrackedExportImportOperation | null = null;\n\n  @computedFrom('item.status', 'item.value')\n  private get status(): string | null {\n    if(this.item != null && this.isPartialSuccess(this.item)) return 'partial-success';\n    return this.item?.status ?? null;\n  }\n\n  @computedFrom('item.status', 'item.value')\n  private get iconName(): string {\n    if(this.item?.status === OperationStatus.Error) return 'System/Tabler/X';\n    if(this.item != null && this.isPartialSuccess(this.item)) return 'System/Tabler/Alert-Triangle';\n    if(this.item?.status === OperationStatus.Success) return 'System/Tabler/Check';\n\n    return 'System/Tabler/Activity';\n  }\n\n  @computedFrom('item.status', 'item.value')\n  private get showReport(): boolean {\n    return this.item != null && this.isPartialSuccess(this.item);\n  }\n\n  @computedFrom('item.value')\n  private get reportErrors(): Array<MediaImportReportFile> {\n    const errors: Array<MediaImportReportFile> = [];\n    if(this.item?.type === TrackedOperationType.Import\n      && this.item.status === OperationStatus.Success) {\n      const itm = this.item as TrackedImportOperation<MediaImportWorkerReturnValue>;\n      errors.push(\n        ...itm.value?.errors?.nameAlreadyExists ?? [],\n        ...itm.value?.errors?.unknown ?? [],\n      );\n    }\n    return errors;\n  }\n\n  private isPartialSuccess(item: TrackedExportImportOperation): boolean {\n    return !!(item.type === TrackedOperationType.Import\n      && item.status === OperationStatus.Success\n      && (\n        (item as TrackedImportOperation<MediaImportWorkerReturnValue>).value?.errors?.nameAlreadyExists?.length\n        || (item as TrackedImportOperation<MediaImportWorkerReturnValue>).value?.errors?.unknown?.length\n      )\n    );\n  }\n}","import { autoinject, bindable } from 'aurelia-framework';\nimport { OperationStatus } from 'common/dto/other/operation.response';\nimport { assertNotNullOrUndefined } from 'common/utils/assert';\nimport { ExportImportService, OperationContext, TrackedExportImportOperation, TrackedExportOperation, TrackedImportOperation, TrackedOperationType } from 'services/ExportImportService';\n\nexport type OperationStatusListReturnValue<TValue = unknown> = { operationId: number; value: TValue  };\n\n@autoinject()\nexport class OperationStatusList {\n  @bindable() public operationContext: OperationContext | null = null;\n  @bindable() public returnValues: Array<OperationStatusListReturnValue<unknown>> = [];\n\n  private imports: Array<TrackedImportOperation> = [];\n  private exports: Array<TrackedExportOperation> = [];\n\n  constructor(\n    private exportImportService: ExportImportService,\n  ) { }\n\n  protected attached(): void {\n    assertNotNullOrUndefined(this.operationContext, 'operationContext cannot be null or undefined');\n    this.exportImportService.subscribeToOperations(this, this.operationContext, this.updateOperations.bind(this));\n  }\n\n  protected detached(): void {\n    this.exportImportService.disposeSubscriptions(this);\n  }\n\n  private updateOperations(trackedOperations: Array<TrackedExportImportOperation>): void {\n    this.imports = trackedOperations.filter((op): op is TrackedImportOperation => op.type === TrackedOperationType.Import);\n    this.exports = trackedOperations.filter((op): op is TrackedExportOperation => op.type === TrackedOperationType.Export);\n\n    // update return values\n    this.returnValues = this.imports.filter(\n      i=> i.status === OperationStatus.Success && i.value != null\n    ).map(i => ({ operationId: i.id, value: i.value }));\n  }\n}"],"names":[],"sourceRoot":""}