{"version":3,"file":"app-73b5434b.f584a1446b2fc034d810.bundle.js","mappings":"AAGA","sources":["webpack://lernplattform-admin-frontend/./src/resources/elements/dropdown-button/dropdown-button.html","webpack://lernplattform-admin-frontend/./src/resources/elements/edit-answer-form/edit-answer-form.html","webpack://lernplattform-admin-frontend/./src/resources/elements/edit-lt-question-form/edit-lt-question-form.html","webpack://lernplattform-admin-frontend/./src/resources/elements/edit-question-form/edit-question-form.html","webpack://lernplattform-admin-frontend/./src/resources/elements/error-block/error-block.html","webpack://lernplattform-admin-frontend/./src/resources/elements/export-details-billing-form/export-details-billing-form.html","webpack://lernplattform-admin-frontend/./src/resources/elements/export-sap-billing-form/export-sap-billing-form.html","webpack://lernplattform-admin-frontend/./src/resources/elements/export-sap-form/export-sap-form.html","webpack://lernplattform-admin-frontend/./src/resources/elements/external-api-course-license/external-api-course-license.html","webpack://lernplattform-admin-frontend/./src/resources/elements/external-api-log/external-api-log.html","webpack://lernplattform-admin-frontend/./src/resources/elements/external-api-overview/external-api-overview.html","webpack://lernplattform-admin-frontend/./src/resources/elements/external-api-sync-queue/external-api-sync-queue.html","webpack://lernplattform-admin-frontend/./src/resources/elements/dropdown-button/dropdown-button.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/edit-answer-form/edit-answer-form.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/edit-lt-question-form/edit-lt-question-form.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/edit-question-form/edit-question-form.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/error-block/error-block.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/export-details-billing-form/export-details-billing-form.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/export-sap-billing-form/export-sap-billing-form.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/export-sap-form/export-sap-form.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/external-api-course-license/external-api-course-license.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/external-api-log/external-api-log.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/external-api-overview/external-api-overview.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/external-api-sync-queue/external-api-sync-queue.ts"],"sourcesContent":["// Module\nvar code = \"<template class=\\\"dropdown-button dropdown-button--theme-${theme} ${ disabled ? 'dropdown-button--disabled' : '' }\\\"> <span data-toggle=\\\"dropdown\\\" ref=\\\"buttonRef\\\" click.delegate=\\\"toggleShowMenu()\\\"> <slot name=\\\"button\\\"> <button type=\\\"button\\\" disabled.to-view=\\\"disabled\\\" class=\\\"btn btn-sm btn-secondary dropdown-toggle\\\">${label}</button> </slot> </span> <div class=\\\"dropdown-menu show popper-tooltip ${ showMenu ? '' : 'popper-tooltip--hidden' }\\\" ref=\\\"dropdownRef\\\" role=\\\"dialog\\\" set-false-on-outside-click.two-way=\\\"showMenu\\\"> <div if.to-view=\\\"showArrow\\\" class=\\\"popper-arrow\\\" data-popper-arrow></div> <slot></slot> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"row\\\"> <div class=\\\"col-12\\\"> <div class=\\\"card\\\"> <div class=\\\"card-header\\\"> <h1 class=\\\"card-title\\\" t=\\\"pages.questions.titleAnswer\\\" t-params.to-view=\\\"{ letter: letter }\\\"></h1> <div class=\\\"form-group mb-0 ml-auto\\\"> <label class=\\\"custom-control custom-checkbox mb-0\\\"> <input type=\\\"checkbox\\\" class=\\\"custom-control-input\\\" input.delegate=\\\"handleIsCorrectChanged($event)\\\" checked.to-view=\\\"isCorrect\\\"> <span class=\\\"custom-control-label\\\" t=\\\"pages.questions.answerCorrect\\\"></span> </label> </div> </div> <div class=\\\"card-body\\\"> <div if.to-view=\\\"textVisible\\\" class=\\\"row\\\"> <div class=\\\"form-group col-12\\\"> <label class=\\\"form-label\\\" t=\\\"pages.questions.textLabel\\\"></label> <textarea class=\\\"form-control\\\" required=\\\"true\\\" value.two-way=\\\"text\\\"></textarea> </div> </div> <div if.to-view=\\\"answerMediaType === MediaType.Picture || answerMediaType === MediaType.PictureAndText\\\" class=\\\"row\\\"> <div class=\\\"col-12\\\"> <label class=\\\"form-label\\\" t=\\\"pages.questions.pictureLabel\\\"></label> </div> <div class=\\\"col-8\\\"> <preview-image image-src.to-view=\\\"pictureUrl\\\" size=\\\"small\\\"></preview-image> </div> <div class=\\\"col-4\\\"> <button class=\\\"btn btn-secondary btn-sm w-100\\\" click.delegate=\\\"handleSelectPictureClick()\\\" t=\\\"pages.questions.${ pictureUrl ? 'editImage' : 'selectImage' }\\\"></button> </div> </div> <audio-select-form if.to-view=\\\"answerMediaType === MediaType.Audio\\\" t=\\\"[title]pages.questions.audioLabel\\\" course-id.to-view=\\\"courseId\\\" audio-id.two-way=\\\"audioId\\\" audio-url.to-view=\\\"audioUrl\\\"></audio-select-form> </div> </div> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"row\\\"> <div class=\\\"col-12\\\"> <div class=\\\"card\\\"> <div class=\\\"card-header\\\"> <h1 class=\\\"card-title\\\" t=\\\"pages.questions.titleQuestion\\\"></h1> <div class=\\\"form-group mb-0 ml-auto\\\"> <label class=\\\"custom-control custom-checkbox mb-0\\\"> <input type=\\\"checkbox\\\" class=\\\"custom-control-input\\\" checked.two-way=\\\"learningOnly\\\"> <span class=\\\"custom-control-label text-nowrap\\\" t=\\\"pages.questions.labelLearningOnly\\\"></span> </label> </div> </div> <div class=\\\"card-body\\\"> <div class=\\\"row\\\"> <div class=\\\"col-12\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"pages.questions.textLabel\\\"></label> <textarea class=\\\"form-control\\\" value.two-way=\\\"text\\\"></textarea> </div> </div> </div> <div class=\\\"row\\\"> <div class=\\\"col-12\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"pages.questions.helpTextLabel\\\"></label> <textarea class=\\\"form-control\\\" value.two-way=\\\"helpText\\\"></textarea> </div> </div> </div> </div> </div> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"row\\\"> <div class=\\\"col-12\\\"> <div class=\\\"card\\\"> <div class=\\\"card-header\\\"> <h1 class=\\\"card-title\\\" t=\\\"pages.questions.titleQuestion\\\"></h1> <div class=\\\"form-group mb-0 ml-auto\\\"> <label class=\\\"custom-control custom-checkbox mb-0\\\"> <input type=\\\"checkbox\\\" class=\\\"custom-control-input\\\" checked.two-way=\\\"question.learningOnly\\\"> <span class=\\\"custom-control-label text-nowrap\\\" t=\\\"pages.questions.labelLearningOnly\\\"></span> </label> </div> </div> <div class=\\\"card-body\\\"> <div if.to-view=\\\"questionMediaType === MediaType.Picture\\\" class=\\\"row\\\"> <div class=\\\"col-12\\\"> <label class=\\\"form-label\\\" t=\\\"pages.questions.imageLabel\\\"></label> </div> <div class=\\\"col-10\\\"> <div class=\\\"form-group\\\"> <exam-image if.to-view=\\\"originalQuestion.picture.url\\\" alt-text.to-view=\\\"question.text\\\" img-src.to-view=\\\"originalQuestion.picture.url\\\" blink-img-src.to-view=\\\"originalQuestion.pictureBlink.url\\\" blur-hash.to-view=\\\"originalQuestion.pictureBlurHash\\\" blink-blur-hash.to-view=\\\"originalQuestion.pictureBlinkBlurHash\\\" enable-zoom.to-view=\\\"false\\\"></exam-image> </div> </div> <div class=\\\"col-2\\\"> <div class=\\\"form-group\\\"> <button class=\\\"btn btn-secondary btn-sm w-100 mb-2\\\" click.delegate=\\\"handleSelectQuestionImage()\\\" t=\\\"pages.questions.${originalQuestion.picture.url ? 'editImage' : 'selectImage'}\\\"></button> <button if.to-view=\\\"originalQuestion.picture.url\\\" class=\\\"btn btn-danger btn-sm w-100\\\" click.delegate=\\\"handleDeleteQuestionImage()\\\" t=\\\"globals.delete\\\"></button> </div> <div class=\\\"form-group\\\"> <button if.to-view=\\\"originalQuestion.picture.url\\\" class=\\\"btn btn-secondary btn-sm w-100 mb-2\\\" click.delegate=\\\"handleSelectQuestionBlinkImage()\\\" t=\\\"pages.questions.${originalQuestion.pictureBlink.url ? 'editBlinkImage' : 'selectBlinkImage'}\\\"></button> <button if.to-view=\\\"originalQuestion.pictureBlink.url\\\" class=\\\"btn btn-danger btn-sm w-100\\\" click.delegate=\\\"handleDeleteQuestionBlinkImage()\\\" t=\\\"pages.questions.deleteBlinkImage\\\"></button> </div> </div> </div> <audio-select-form if.to-view=\\\"questionMediaType === MediaType.Audio\\\" t=\\\"[title]pages.questions.audioLabel\\\" course-id.to-view=\\\"courseId\\\" audio-id.two-way=\\\"question.audioId\\\" audio-url.to-view=\\\"originalQuestion.audioUrl\\\"></audio-select-form> <div class=\\\"row\\\"> <div class=\\\"col-md-12\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"pages.questions.textLabel\\\"></label> <textarea class=\\\"form-control\\\" value.two-way=\\\"question.text\\\"></textarea> </div> </div> </div> <div class=\\\"row\\\"> <div class=\\\"col-md-12\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"pages.questions.helpTextLabel\\\"></label> <textarea class=\\\"form-control\\\" value.two-way=\\\"question.helpText\\\"></textarea> </div> </div> </div> </div> </div> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <div class=\\\"container text-center\\\"> <div class=\\\"display-1 text-muted mb-5\\\"><i class=\\\"si si-exclamation\\\"></i>${ code }</div> <h1 class=\\\"h2 mb-3\\\">${ title }</h1> <p class=\\\"h4 text-muted font-weight-normal mb-7\\\">${ message }</p> <a class=\\\"btn btn-primary\\\" route-href=\\\"route: home\\\"> <i class=\\\"fe fe-arrow-left mr-2\\\"></i>${ 'globals.toHome' | t } </a> </div> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <form submit.trigger=\\\"downloadDetailsCsv()\\\" class=\\\"card export-details-billing-form\\\"> <div class=\\\"card-header\\\"> <h3 class=\\\"card-title\\\" t=\\\"pages.csv-export.exportDetailsTitle\\\"></h3> </div> <div class=\\\"card-body export-details-billing-form__body\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"pages.csv-export.year\\\"></label> <input type=\\\"number\\\" class=\\\"form-control\\\" min=\\\"2019\\\" max=\\\"2030\\\" value.two-way=\\\"selectedYear | number\\\"> </div> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"pages.csv-export.quarter\\\"></label> <select value.two-way=\\\"selectedQuarter\\\" class=\\\"custom-select\\\"> <option repeat.for=\\\"quarter of quarters\\\" model.bind=\\\"quarter\\\">${quarter}</option> </select> </div> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"pages.csv-export.csvTypeLabel\\\"></label> <select value.two-way=\\\"selectedCsvType\\\" class=\\\"custom-select\\\"> <option repeat.for=\\\"csvType of csvTypes\\\" model.bind=\\\"csvType.csvType\\\" t=\\\"${csvType.csvTypeTk}\\\"></option> </select> </div> <div class=\\\"form-group export-details-billing-form__checkbox\\\"> <label class=\\\"form-label\\\" t=\\\"pages.csv-export.exportDetailsIncludeNonBillable\\\"></label> <label class=\\\"custom-control custom-checkbox custom-control-inline\\\"> <input type=\\\"checkbox\\\" class=\\\"custom-control-input\\\" checked.bind=\\\"includeNonBillableActivities\\\"> <span class=\\\"custom-control-label\\\" t=\\\"globals.include\\\"></span> </label> </div> </div> <div class=\\\"card-footer text-right\\\"> <button class=\\\"btn btn-primary ml-auto\\\" type=\\\"submit\\\" t=\\\"pages.csv-export.generateCsvBtn\\\"></button> </div> </form> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <form submit.trigger=\\\"downloadSAPCsv()\\\" class=\\\"card export-sap-billing-form\\\"> <div class=\\\"card-header\\\"> <h3 class=\\\"card-title\\\" t=\\\"pages.csv-export.exportSAP\\\"></h3> </div> <div class=\\\"card-body export-sap-billing-form__body\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"pages.csv-export.year\\\"></label> <input type=\\\"number\\\" class=\\\"form-control\\\" min=\\\"2019\\\" max=\\\"2030\\\" value.two-way=\\\"selectedYear | number\\\"> </div> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"pages.csv-export.quarter\\\"></label> <select value.two-way=\\\"selectedQuarter\\\" class=\\\"custom-select\\\"> <option repeat.for=\\\"quarter of quarters\\\" model.bind=\\\"quarter\\\">${quarter}</option> </select> </div> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"globals.clientType\\\"></label> <multi-select-combo-box selected-items-changed.trigger=\\\"selectedClientTypeError = false\\\" total-items.to-view=\\\"availableClientTypes\\\" label-property-name=\\\"label\\\" is-invalid.to-view=\\\"selectedClientTypeError\\\" selected-items.to-view=\\\"selectedClientTypes\\\"></multi-select-combo-box> <div if.to-view=\\\"selectedClientTypeError\\\" class=\\\"invalid-feedback d-flex\\\" t=\\\"pages.csv-export.clientTypeMandatory\\\"></div> </div> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"pages.csv-export.csvTypeLabel\\\"></label> <select value.two-way=\\\"selectedCsvType\\\" class=\\\"custom-select\\\"> <option repeat.for=\\\"csvType of csvTypes\\\" model.bind=\\\"csvType.csvType\\\" t=\\\"${csvType.csvTypeTk}\\\"></option> </select> </div> <div class=\\\"form-group export-sap-billing-form__checkbox\\\"> <label class=\\\"form-label\\\" t=\\\"pages.csv-export.tenantsWithoutActivities\\\"></label> <label class=\\\"custom-control custom-checkbox custom-control-inline\\\"> <input type=\\\"checkbox\\\" class=\\\"custom-control-input\\\" checked.bind=\\\"selectedTenantsWhichSoldNone\\\"> <span class=\\\"custom-control-label\\\" t=\\\"globals.include\\\"></span> </label> </div> </div> <div class=\\\"card-footer text-right\\\"> <button class=\\\"btn btn-primary ml-auto\\\" type=\\\"submit\\\" t=\\\"pages.csv-export.generateCsvBtn\\\"></button> </div> </form> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"card\\\"> <div class=\\\"card-header\\\"> <h3 class=\\\"card-title\\\" t=\\\"pages.csv-export.exportSAP\\\"></h3> </div> <div class=\\\"card-body\\\"> <div class=\\\"row\\\"> <div class=\\\"col-md-3\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"pages.csv-export.year\\\"></label> <input type=\\\"number\\\" class=\\\"form-control\\\" min=\\\"2019\\\" max=\\\"2024\\\" value.two-way=\\\"selectedYear | number\\\"> </div> </div> <div class=\\\"col-md-3\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"pages.csv-export.quarter\\\"></label> <select value.two-way=\\\"selectedQuarter\\\" class=\\\"custom-select\\\"> <option repeat.for=\\\"quarter of quarters\\\" model.bind=\\\"quarter\\\">${quarter}</option> </select> </div> </div> <div class=\\\"col-md-3\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"globals.clientType\\\"></label> <multi-select-combo-box selected-items-changed.trigger=\\\"selectedClientTypeError = false\\\" total-items.to-view=\\\"availableClientTypes\\\" label-property-name=\\\"label\\\" is-invalid.to-view=\\\"selectedClientTypeError\\\" selected-items.to-view=\\\"selectedClientTypes\\\"></multi-select-combo-box> <div if.to-view=\\\"selectedClientTypeError\\\" class=\\\"invalid-feedback d-flex\\\" t=\\\"pages.csv-export.clientTypeMandatory\\\"></div> </div> </div> <div class=\\\"col-md-3\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"pages.csv-export.csvTypeLabel\\\"></label> <select value.two-way=\\\"selectedCsvType\\\" class=\\\"custom-select\\\"> <option repeat.for=\\\"csvType of csvTypes\\\" model.bind=\\\"csvType.csvType\\\" t=\\\"${csvType.csvTypeTk}\\\"></option> </select> </div> </div> </div> <div class=\\\"row\\\"> <div class=\\\"col-md-12\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"pages.csv-export.tenantsWhichSoldNone\\\"></label> <label class=\\\"custom-control custom-checkbox custom-control-inline\\\"> <input type=\\\"checkbox\\\" class=\\\"custom-control-input\\\" checked.bind=\\\"selectedTenantsWhichSoldNone\\\"> <span class=\\\"custom-control-label\\\" t=\\\"globals.include\\\"></span> </label> </div> </div> </div> <div class=\\\"row\\\"> <div class=\\\"col-md-12\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"pages.csv-export.freeCodes\\\"></label> <label class=\\\"custom-control custom-checkbox custom-control-inline\\\"> <input type=\\\"checkbox\\\" class=\\\"custom-control-input\\\" checked.bind=\\\"selectedFreeCodesIncluded\\\"> <span class=\\\"custom-control-label\\\" t=\\\"globals.include\\\"></span> </label> </div> </div> </div> </div> <div class=\\\"card-footer text-right\\\"> <button class=\\\"btn btn-primary ml-auto\\\" click.delegate=\\\"downloadSAPCsv()\\\" t=\\\"pages.csv-export.generateCsvBtn\\\"></button> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"external-api-course-license\\\"> <div class=\\\"d-flex mb-4\\\"> <button-standard class=\\\"ml-auto\\\" t=\\\"[btnText]pages.external-api.addCourseLicense\\\" click.delegate=\\\"addCourseLicense()\\\" icon-name=\\\"System/Tabler/Plus\\\" btn-color=\\\"secondary\\\"></button-standard> </div> <div class=\\\"row row-cards row-deck\\\"> <div class=\\\"col-12\\\"> <custom-table columns.to-view=\\\"tableColumns\\\" extendable=\\\"true\\\" table-id=\\\"external-api-course-license\\\" show-filters.to-view=\\\"false\\\" hide-footer.to-view=\\\"true\\\" hide-controls.to-view=\\\"false\\\" get-shown-entries-data.call=\\\"fetchTableData(limit, offset)\\\" refresh-version.to-view=\\\"tableRefreshVersion\\\"></custom-table> </div> </div> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <div class=\\\"row row-cards row-deck\\\"> <div class=\\\"col-12\\\"> <custom-table columns.to-view=\\\"columnsLog\\\" extendable=\\\"true\\\" table-id=\\\"external-api-log\\\" get-shown-entries-data.call=\\\"fetchTableData(limit, offset)\\\"></custom-table> </div> </div> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <div class=\\\"card\\\"> <div class=\\\"card-header\\\"> <h3 class=\\\"card-title\\\" t=\\\"pages.external-api.status\\\"></h3> </div> <div class=\\\"card-body\\\"> <template if.to-view=\\\"status\\\"> <div class=\\\"row\\\"> <span class=\\\"font-weight-bold col-4\\\" t=\\\"pages.external-api.apiKey.label\\\"></span> <span if.to-view=\\\"status.apiKey\\\">${ status.apiKey }</span> <span else t=\\\"pages.external-api.apiKey.notCreated\\\"></span> </div> <template if.to-view=\\\"status.apiKey\\\"> <div class=\\\"row\\\"> <span class=\\\"font-weight-bold col-4\\\" t=\\\"pages.external-api.syncStatus.label\\\"></span> <span class=\\\"external-api-overview__status external-api-overview__status--sync-${status.sync}\\\" t=\\\"pages.external-api.syncStatus.${status.sync}\\\"></span> </div> <template if.to-view=\\\"status.sync !== ExternalApiSyncStatus.None\\\"> <div class=\\\"row\\\"> <span class=\\\"font-weight-bold col-4\\\" t=\\\"pages.external-api.outgoingApiKeyStatus.label\\\"></span> <span class=\\\"external-api-overview__status external-api-overview__status--outgoing-api-key-${status.outgoingApiKey}\\\" t=\\\"pages.external-api.outgoingApiKeyStatus.${status.outgoingApiKey}\\\"></span> </div> <div class=\\\"row\\\"> <span class=\\\"font-weight-bold col-4\\\" t=\\\"pages.external-api.errorStatus.label\\\"></span> <span class=\\\"external-api-overview__status external-api-overview__status--error-${status.error}\\\"> ${ `pages.external-api.errorStatus.${status.error}` | t}${status.errorMessage ? `: ${status.errorMessage}` : ''} </span> </div> <div class=\\\"row\\\"> <span class=\\\"font-weight-bold col-4\\\" t=\\\"pages.external-api.queueLength.label\\\"></span> <span class=\\\"external-api-overview__status external-api-overview__status--queue-length-${status.queueLength}\\\">${'pages.external-api.queueLength.value' | t:{ postProcess: 'interval', count: status.queueLength } }</span> </div> </template> </template> </template> <div else t=\\\"pages.external-api.loading\\\"></div> </div> <div class=\\\"card-footer text-right\\\"> <button class=\\\"btn btn-primary ml-auto\\\" click.delegate=\\\"createNewKey()\\\" t=\\\"pages.external-api.generateNewKey\\\"></button> </div> </div> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <div class=\\\"row row-cards row-deck\\\"> <div class=\\\"col-12\\\"> <custom-table columns.to-view=\\\"columnsSyncQueue\\\" extendable=\\\"true\\\" table-id=\\\"external-api-sync-queue\\\" get-shown-entries-data.call=\\\"fetchTableData(limit, offset)\\\" refresh-version.to-view=\\\"tableRefreshVersion\\\"></custom-table> </div> </div> </template> \";\n// Exports\nexport default code;","import { autoinject, bindable } from 'aurelia-framework';\nimport { createPopper, Instance } from '@popperjs/core/lib/popper-lite';\nimport arrow from '@popperjs/core/lib/modifiers/arrow';\nimport offset from '@popperjs/core/lib/modifiers/offset';\nimport { Placement, PositioningStrategy } from '@popperjs/core';\n\nexport enum Theme {\n  Default = 'default',\n  Uce = 'uce',\n}\n\n@autoinject()\nexport class DropdownButton {\n  @bindable() public showMenu = false;\n  @bindable() public label = '';\n  @bindable() public offset: Array<number> = [0, 16];\n  @bindable() public theme = Theme.Default;\n  @bindable() public showArrow = true;\n  @bindable() public closeOnInsideClick = true;\n  @bindable() public disabled = false;\n  @bindable() public placement: Placement = 'bottom';\n  @bindable() public positioningStrategy: PositioningStrategy = 'fixed';\n\n  public buttonRef!: HTMLElement;\n  public dropdownRef!: HTMLElement;\n\n  private popper?: Instance;\n\n  protected attached(): void {\n    this.popper = createPopper(this.buttonRef, this.dropdownRef, {\n      placement: this.placement,\n      strategy: this.positioningStrategy,\n      modifiers: [\n        ...(this.showArrow ? [arrow] : []),\n        offset,\n        {\n          name: 'offset',\n          options: {\n            offset: this.offset,\n          },\n        },\n      ],\n    });\n\n    if(this.closeOnInsideClick) {\n      this.dropdownRef.addEventListener('click', () => this.toggleShowMenu());\n    }\n  }\n\n  protected detached(): void {\n    this.popper?.destroy();\n  }\n\n  private toggleShowMenu(): void {\n    this.showMenu = !this.showMenu;\n    if(this.showMenu) {\n      this.popper?.forceUpdate();\n    }\n  }\n}\n","import { autoinject, bindable, computedFrom } from 'aurelia-framework';\nimport { GalleryMediaType } from 'common/enum/gallery.enum';\nimport { DomUtils } from 'common/utils/DomUtils';\nimport { assertNotNullOrUndefined } from 'common/utils/assert';\nimport { CustomDialogService } from '../../../services/CustomDialogService';\nimport { MediaType } from '../../dialogs/edit-question-dialog/edit-question-dialog';\n\n/**\n * @event {AnswerCheckedEvent} answer-checked\n */\n@autoinject()\nexport class EditAnswerForm {\n  @bindable() public courseId: number | null = null;\n  @bindable() public showText: boolean = true;\n  @bindable() public text: string = '';\n  @bindable() public letter: string = 'A';\n  @bindable() public isCorrect: boolean = false;\n  @bindable() public audioUrl: string | null = null;\n  @bindable() public audioId: number | null = null;\n  @bindable() public pictureId: number | null = null;\n  @bindable() public pictureUrl: string | null = null;\n  @bindable() public answerMediaType: MediaType = MediaType.Text;\n\n  private MediaType = MediaType;\n  private domElement: HTMLElement;\n\n  constructor(\n    private dialogService: CustomDialogService,\n    element: Element\n  ) {\n    this.domElement = element as HTMLElement;\n  }\n\n  private async handleSelectPictureClick(): Promise<void> {\n    assertNotNullOrUndefined(this.courseId, 'courseId cannot be null or undefined');\n    const result = await this.dialogService.showProviderMediaSelect({ courseId: this.courseId, selectedMediaType: GalleryMediaType.Picture });\n    if(result?.type === GalleryMediaType.Picture) {\n      this.pictureId = result.value.id;\n      this.pictureUrl = result.value.url;\n    }\n  }\n\n  private handleIsCorrectChanged(event: Event): void {\n    const target = event.target as HTMLInputElement;\n    DomUtils.fireEvent<AnswerCheckedEvent['detail']>(this.domElement, {\n      name: 'answer-checked',\n      bubbles: true,\n      detail: {\n        checked: target.checked,\n      },\n    });\n  }\n\n  @computedFrom('showText', 'answerMediaType')\n  private get textVisible(): boolean {\n    return this.showText && [MediaType.Text, MediaType.PictureAndText].includes(this.answerMediaType);\n  }\n}\n\nexport type AnswerCheckedEvent = Event & { detail: { checked: boolean } };\n","import { bindable } from 'aurelia-templating';\n\nexport class EditLtQuestionForm {\n  @bindable() public text: string = '';\n  @bindable() public helpText: string = '';\n  @bindable() public learningOnly: boolean = false;\n}\n","import { bindable, autoinject } from 'aurelia-framework';\nimport { IQuestionDto, IQuestionEditDto } from 'common/dto/course/content/question.interface';\nimport { GalleryMediaType } from 'common/enum/gallery.enum';\nimport { assertNotNullOrUndefined } from 'common/utils/assert';\nimport { MediaType } from '../../dialogs/edit-question-dialog/edit-question-dialog';\nimport { CustomDialogService } from '../../../services/CustomDialogService';\n\n@autoinject()\nexport class EditQuestionForm {\n  @bindable() public courseId: number | null = null;\n  @bindable() public originalQuestion: IQuestionDto | null = null;\n  @bindable() public question: IQuestionEditDto | null = null;\n  @bindable() public questionMediaType: MediaType = MediaType.Picture;\n  private MediaType = MediaType;\n\n  constructor(private dialogService: CustomDialogService) { }\n\n  private handleDeleteQuestionImage(): void {\n    assertNotNullOrUndefined(this.question, 'question cannot be null or undefined');\n    assertNotNullOrUndefined(this.originalQuestion, 'originalQuestion cannot be null or undefined');\n\n    this.question.pictureId = null;\n    this.originalQuestion.picture = null;\n  }\n\n  private handleDeleteQuestionBlinkImage(): void {\n    assertNotNullOrUndefined(this.question, 'question cannot be null or undefined');\n    assertNotNullOrUndefined(this.originalQuestion, 'originalQuestion cannot be null or undefined');\n\n    this.question.pictureBlinkId = null;\n    this.originalQuestion.pictureBlink = null;\n  }\n\n  private async handleSelectQuestionImage(): Promise<void> {\n    assertNotNullOrUndefined(this.question, 'question cannot be null or undefined');\n    assertNotNullOrUndefined(this.courseId, 'courseId cannot be null or undefined');\n    assertNotNullOrUndefined(this.originalQuestion, 'originalQuestion cannot be null or undefined');\n\n    const result = await this.dialogService.showProviderMediaSelect({ courseId: this.courseId, selectedMediaType: GalleryMediaType.Picture });\n    if(result?.type === GalleryMediaType.Picture) {\n      this.question.pictureId = result.value.id;\n      this.originalQuestion.picture = {\n        id: result.value.id,\n        url: result.value.url,\n        blurHash: result.value.blurHash,\n        width: result.value.width,\n        height: result.value.height\n      };\n    }\n  }\n\n  private async handleSelectQuestionBlinkImage(): Promise<void> {\n    assertNotNullOrUndefined(this.question, 'question cannot be null or undefined');\n    assertNotNullOrUndefined(this.courseId, 'courseId cannot be null or undefined');\n    assertNotNullOrUndefined(this.originalQuestion, 'originalQuestion cannot be null or undefined');\n\n    const result = await this.dialogService.showProviderMediaSelect({ courseId: this.courseId, selectedMediaType: GalleryMediaType.Picture });\n    if(result?.type === GalleryMediaType.Picture) {\n      this.question.pictureBlinkId = result.value.id;\n      this.originalQuestion.pictureBlink = {\n        id: result.value.id,\n        url: result.value.url,\n        blurHash: result.value.blurHash,\n        width: result.value.width,\n        height: result.value.height\n      };\n    }\n  }\n}\n","import { bindable } from 'aurelia-framework';\n\nexport class ErrorBlock {\n  @bindable public code = '';\n  @bindable public title = '';\n  @bindable public message = '';\n}\n","import { autoinject } from 'aurelia-framework';\nimport { I18N } from 'aurelia-i18n';\nimport { ITenantBillingDetailsExportQueryDto } from 'common/dto/tenant/billing/tenant.billing.interface';\nimport { LogUtils } from 'common/utils/LogUtils';\nimport { TenantBillingsApiService } from 'services/api/TenantBillingsApiService';\nimport { ToastService } from '../../../services/ToastService';\nimport { CsvExport } from '../../classes/csv-export';\n\n@autoinject()\nexport class ExportDetailsBillingForm extends CsvExport {\n  private includeNonBillableActivities = false;\n\n  constructor(\n    private tenantBillingsApiService: TenantBillingsApiService,\n    private toastService: ToastService,\n    private i18n: I18N\n  ) { super(); }\n\n  private async downloadDetailsCsv(): Promise<void> {\n    const query: ITenantBillingDetailsExportQueryDto = {\n      quarter: this.selectedQuarter,\n      year: this.selectedYear,\n      includeNonBillableActivities: this.includeNonBillableActivities,\n      exportType: this.selectedCsvType,\n    };\n    const fileName = `${this.i18n.tr('globals.fileNameDetailsExport')}.csv`;\n    try {\n      await this.tenantBillingsApiService.getBillingDetailsExport(query, fileName);\n      this.toastService.success('pages.csv-export.exportSuccess');\n    } catch(error) {\n      this.toastService.error('pages.csv-export.exportError', {}, error);\n      LogUtils.exception(error);\n    }\n  }\n}\n","import { autoinject } from 'aurelia-framework';\nimport { I18N } from 'aurelia-i18n';\nimport { ITenantBillingSapExportQueryDto } from 'common/dto/tenant/billing/tenant.billing.interface';\nimport { ClientType } from 'common/enum/tenant.enum';\nimport { LogUtils } from 'common/utils/LogUtils';\nimport { TenantBillingsApiService } from 'services/api/TenantBillingsApiService';\nimport { ToastService } from '../../../services/ToastService';\nimport { CsvExport } from '../../classes/csv-export';\n\ninterface IClientTypeOption {\n  type: ClientType;\n  label: string;\n}\n\n@autoinject()\nexport class ExportSapBillingForm extends CsvExport {\n  private availableClientTypes: IClientTypeOption[] = [];\n  private selectedClientTypes: IClientTypeOption[] = [];\n  private selectedClientTypeError: boolean = false;\n\n  constructor(\n    private tenantBillingsApiService: TenantBillingsApiService,\n    private toastService: ToastService,\n    private i18n: I18N\n  ) {\n    super();\n    this.availableClientTypes = Object.values(ClientType).map(cT => ({ type: cT, label: this.i18n.tr(`globals.clientTypes.${cT}`) }));\n    this.selectedClientTypes = this.availableClientTypes.filter(cT => cT.type !== ClientType.Test);\n  }\n\n  private async downloadSAPCsv(): Promise<void> {\n    const clientTypes = this.selectedClientTypes.map(cT => cT.type);\n    this.selectedClientTypeError = !this.selectedClientTypes.length;\n\n    const query: ITenantBillingSapExportQueryDto = {\n      quarter: this.selectedQuarter,\n      year: this.selectedYear,\n      includeTenantsWithoutActivities: this.selectedTenantsWhichSoldNone,\n      clientTypes,\n      exportType: this.selectedCsvType,\n    };\n    if(this.selectedClientTypeError) return;\n    const fileName = `${this.i18n.tr('globals.fileNameSAPExport')}.csv`;\n    try {\n      await this.tenantBillingsApiService.getBillingSapExport(query, fileName);\n      this.toastService.success('pages.csv-export.exportSuccess');\n    } catch(error) {\n      this.toastService.error('pages.csv-export.exportError', {}, error);\n      LogUtils.exception(error);\n    }\n  }\n}","import { autoinject } from 'aurelia-framework';\nimport { I18N } from 'aurelia-i18n';\nimport { IAccessCodeExportQueryDto } from 'common/dto/tenant/management/tenant.management.interface';\nimport { ClientType } from 'common/enum/tenant.enum';\nimport { LogUtils } from 'common/utils/LogUtils';\nimport { TenantApiService } from '../../../services/api/TenantApiService';\nimport { ToastService } from '../../../services/ToastService';\nimport { CsvExport } from '../../classes/csv-export';\n\ninterface IClientTypeOption {\n  type: ClientType;\n  label: string;\n}\n\n@autoinject()\nexport class ExportSapForm extends CsvExport {\n  private availableClientTypes: IClientTypeOption[] = [];\n  private selectedClientTypes: IClientTypeOption[] = [];\n  private selectedClientTypeError: boolean = false;\n\n  constructor(\n    private tenantApiService: TenantApiService,\n    private toastService: ToastService,\n    private i18n: I18N\n  ) {\n    super();\n    this.availableClientTypes = Object.values(ClientType).map(cT => ({ type: cT, label: this.i18n.tr(`globals.clientTypes.${cT}`) }));\n    this.selectedClientTypes = this.availableClientTypes.filter(cT => cT.type !== ClientType.Test);\n  }\n\n  private async downloadSAPCsv(): Promise<void> {\n    const clientTypes = this.selectedClientTypes.map(cT => cT.type);\n    this.selectedClientTypeError = !this.selectedClientTypes.length;\n\n    const query: IAccessCodeExportQueryDto = {\n      quarter: this.selectedQuarter,\n      year: this.selectedYear,\n      includeFreeCodes: this.selectedFreeCodesIncluded,\n      includeTenantsWhichSoldNone: this.selectedTenantsWhichSoldNone,\n      tenantId: null,\n      clientTypes\n    };\n    if(this.selectedClientTypeError) return;\n    const fileName = `${this.i18n.tr('globals.fileNameSAPExport')}.csv`;\n    try {\n      await this.tenantApiService.getCsvExport(query, this.selectedCsvType, fileName);\n      this.toastService.success('pages.csv-export.exportSuccess');\n    } catch(error) {\n      this.toastService.error('pages.csv-export.exportError', {}, error);\n      LogUtils.exception(error);\n    }\n  }\n}","import { autoinject } from 'aurelia-framework';\nimport { IExternalApiManagementCourseLicenseAssignmentDto } from 'common/dto/external-api-management/external.api.management.interface';\nimport { ColumnSortDirection } from 'common/dto/filter/filter.enum';\nimport { IFilterDto } from 'common/dto/filter/filter.interface';\nimport { CourseManagementApiService } from '../../../services/api/CourseManagementApiService';\nimport { ExternalApiApiService } from '../../../services/api/ExternalApiApiService';\nimport { CustomDialogService } from '../../../services/CustomDialogService';\nimport { ActionsCell } from '../custom-table/actions-cell/actions-cell';\nimport { CustomTableCell } from '../custom-table/custom-table-cell/custom-table-cell';\nimport { createPrepareServersideSortingFunction, VirtualFilterField } from '../custom-table/custom-table-helpers';\nimport { IColumnDefinition } from '../custom-table/custom-table-interfaces';\n\n@autoinject()\nexport class ExternalApiCourseLicense {\n  private usedCourseIds = new Set<number>();\n  private usedLicenseIds: string[] = [];\n\n  private tableRefreshVersion = 0;\n\n  private filter: IFilterDto<IExternalApiManagementCourseLicenseAssignmentDto> = {\n    offset: 0,\n    limit: 10,\n    order: [\n      {\n        field: 'courseTitle',\n        dir: ColumnSortDirection.ASC,\n      }\n    ],\n    filter: [],\n  };\n\n  private tableColumns: Array<IColumnDefinition<CustomTableCell<IExternalApiManagementCourseLicenseAssignmentDto> | ActionsCell<IExternalApiManagementCourseLicenseAssignmentDto>>> = [\n    {\n      id: 'course',\n      nameTk: 'globals.course',\n      cellViewModel: CustomTableCell,\n      prepareSorting: createPrepareServersideSortingFunction(this.filter, 'courseTitle' as VirtualFilterField),\n      cellOptions: {\n        transformer: e => e.courseTitle,\n      },\n    },\n    {\n      id: 'license',\n      nameTk: 'pages.external-api.licenseId.label',\n      cellViewModel: CustomTableCell,\n      prepareSorting: createPrepareServersideSortingFunction(this.filter, 'licenseId' as VirtualFilterField),\n      cellOptions: {\n        transformer: e => e.licenseId,\n      },\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 fe-edit',\n            clickCallback: e => { this.updateCourseLicense(e); }\n          },\n          'divider',\n          {\n            labelTk: 'globals.delete',\n            icon: 'fe-delete',\n            additionalClasses: 'text-danger',\n            clickCallback: e => { this.deleteCourseLicense(e); }\n          },\n        ]\n      }\n    }\n  ];\n\n  constructor(\n    private api: ExternalApiApiService,\n    private customDialogService: CustomDialogService,\n    private courseManagementApiService: CourseManagementApiService,\n  ) { }\n\n  private async fetchTableData(limit: number, offset: number): Promise<{ total: number; data: Array<IExternalApiManagementCourseLicenseAssignmentDto> }> {\n    this.filter.limit = limit;\n    this.filter.offset = offset;\n\n    const result = await this.api.getCourseLicenseAssignments(this.filter);\n    this.usedCourseIds = new Set(result.rows.map(r => r.courseId));\n    this.usedLicenseIds = result.rows.map(r => r.licenseId);\n\n    return { data: result.rows, total: result.count };\n  }\n\n  private async addCourseLicense(): Promise<void> {\n    const availableCourses = await this.courseManagementApiService.getAvailableRegularCourses();\n    const courseSelection = await this.customDialogService.showCourseLicenseDialog({\n      options: availableCourses.filter(c => !this.usedCourseIds.has(c.id)),\n      usedLicenseIds: this.usedLicenseIds,\n    });\n    if(!courseSelection) return;\n\n    await this.api.createCourseLicenseAssignment({ courseId: courseSelection.course.id, licenseId: courseSelection.licenseId });\n    this.tableRefreshVersion++;\n  }\n\n  private async updateCourseLicense(item: IExternalApiManagementCourseLicenseAssignmentDto): Promise<void> {\n    const availableCourses = await this.courseManagementApiService.getAvailableRegularCourses();\n    const courseSelection = await this.customDialogService.showCourseLicenseDialog({\n      options: availableCourses.filter(c => !this.usedCourseIds.has(c.id) || item.courseId === c.id),\n      usedLicenseIds: this.usedLicenseIds.filter(l => l !== item.licenseId),\n      ...item,\n    });\n    if(!courseSelection || !courseSelection.course || !courseSelection.licenseId) return;\n\n    await this.api.updateCourseLicenseAssignment(item.id, { courseId: courseSelection.course.id, licenseId: courseSelection.licenseId });\n    this.tableRefreshVersion++;\n  }\n\n  private async deleteCourseLicense(item: IExternalApiManagementCourseLicenseAssignmentDto): Promise<void> {\n    if(!await this.customDialogService.confirmDeletion()) return;\n\n    await this.api.deleteCourseLicenseAssignment(item.id);\n    this.tableRefreshVersion++;\n  }\n}\n","import { autoinject } from 'aurelia-framework';\nimport { IExternalApiSyncLogDto } from 'common/dto/external-api/external.api.interface';\nimport { ColumnSortDirection, FilterOperationType } from 'common/dto/filter/filter.enum';\nimport { IFilterDto } from 'common/dto/filter/filter.interface';\nimport {\n  SyncActionStatus,\n  SyncActionType,\n  SyncLogOnlyActionType,\n  SyncLogType\n} from 'common/enum/external-api/sync.enum';\nimport dayjs from 'dayjs';\nimport { DateService } from 'services/DateService';\nimport { ExternalApiApiService } from '../../../services/api/ExternalApiApiService';\nimport { CustomTableCell } from '../custom-table/custom-table-cell/custom-table-cell';\nimport {\n  createPrepareServersideSortingFunction,\n  deepPropertyString,\n  prepareServersideFiltering,\n  VirtualFilterField\n} from '../custom-table/custom-table-helpers';\nimport { IColumnDefinition } from '../custom-table/custom-table-interfaces';\nimport { JsonCell } from '../custom-table/json-cell/json-cell';\n\n@autoinject()\nexport class ExternalApiLog {\n  private logFilter: IFilterDto<IExternalApiSyncLogDto> = {\n    offset: 0,\n    limit: 10,\n    filter: [],\n    order: [{\n      field: 'updatedAt',\n      dir: ColumnSortDirection.DESC,\n    }],\n  };\n  private columnsLog: Array<IColumnDefinition<CustomTableCell<IExternalApiSyncLogDto> | JsonCell<IExternalApiSyncLogDto>>> = [\n    {\n      id: 'updatedAt',\n      nameTk: 'globals.timestamp',\n      prepareSorting: createPrepareServersideSortingFunction(this.logFilter, 'updatedAt'),\n      cellViewModel: CustomTableCell,\n      cellOptions: { transformer: e => this.dateService.formatDateTime(e.updatedAt) },\n      filter: {\n        placeholderTk: 'globals.filter',\n        daterange: true,\n        prepare: v => {\n          const [start, end] = v.split('|');\n          const filterEndDate = end ? (dayjs(end).add(1, 'day')).toISOString() : '';\n          prepareServersideFiltering(this.logFilter, 'updatedAt' as VirtualFilterField, start, FilterOperationType.Gt);\n          prepareServersideFiltering(this.logFilter, 'updatedAt' as VirtualFilterField, filterEndDate, FilterOperationType.Lt);\n        },\n      }\n    },\n    {\n      id: 'type',\n      nameTk: 'globals.type',\n      cellViewModel: CustomTableCell,\n      cellOptions: {\n        tk: log => `pages.external-api.log.types.${log.type}`\n      },\n      prepareSorting: createPrepareServersideSortingFunction(() => this.logFilter, 'type'),\n      filter: {\n        placeholderTk: 'globals.filter',\n        prepare: v => prepareServersideFiltering(this.logFilter, 'type' as VirtualFilterField, v, FilterOperationType.Eq),\n        options: [\n          { keyTk: 'pages.external-api.log.types.incoming', value: SyncLogType.Incoming },\n          { keyTk: 'pages.external-api.log.types.outgoing', value: SyncLogType.Outgoing },\n          { keyTk: 'pages.external-api.log.types.other', value: SyncLogType.Other },\n        ]\n      }\n    },\n    {\n      id: 'actionType',\n      nameTk: 'pages.external-api.log.actionType',\n      cellViewModel: CustomTableCell,\n      cellOptions: {\n        tk: log => `pages.external-api.log.actionTypes.${log.actionType}`\n      },\n      prepareSorting: createPrepareServersideSortingFunction(() => this.logFilter, 'actionType'),\n      filter: {\n        placeholderTk: 'globals.filter',\n        prepare: v => prepareServersideFiltering(this.logFilter, 'actionType' as VirtualFilterField, v, FilterOperationType.Eq),\n        options: [\n          { keyTk: 'pages.external-api.log.actionTypes.create', value: SyncActionType.Create },\n          { keyTk: 'pages.external-api.log.actionTypes.read', value: SyncActionType.Read },\n          { keyTk: 'pages.external-api.log.actionTypes.update', value: SyncActionType.Update },\n          { keyTk: 'pages.external-api.log.actionTypes.delete', value: SyncActionType.Delete },\n          { keyTk: 'pages.external-api.log.actionTypes.unknown', value: SyncActionType.Unknown },\n          { keyTk: 'pages.external-api.log.actionTypes.unlink', value: SyncLogOnlyActionType.Unlink },\n        ]\n      }\n    },\n    {\n      id: 'endpoint',\n      nameTk: 'pages.external-api.log.endpoint',\n      cellViewModel: CustomTableCell,\n      cellOptions: {\n        transformer: deepPropertyString('endpoint')\n      },\n      prepareSorting: createPrepareServersideSortingFunction(() => this.logFilter, 'endpoint'),\n      filter: {\n        placeholderTk: 'globals.filter',\n        prepare: v => prepareServersideFiltering(this.logFilter, 'endpoint', v),\n      },\n      wrap: true\n    },\n    {\n      id: 'status',\n      nameTk: 'globals.status',\n      cellViewModel: CustomTableCell,\n      cellOptions: {\n        tk: log => {\n          switch(log.status) {\n            case SyncActionStatus.Pending:\n            case SyncActionStatus.Success:\n              return `pages.external-api.log.actionStatus.${log.status}`;\n            case SyncActionStatus.ErrorApiKeyRejected:\n              return 'pages.external-api.errorStatus.apiKeyRejected';\n            case SyncActionStatus.ErrorNonblocking:\n              return 'pages.external-api.errorStatus.nonBlocking';\n            case SyncActionStatus.ErrorServerError:\n              return 'pages.external-api.errorStatus.serverError';\n            case SyncActionStatus.ErrorServerUnreachable:\n              return 'pages.external-api.errorStatus.serverUnreachable';\n            case SyncActionStatus.ErrorTimeout:\n              return 'pages.external-api.errorStatus.timeout';\n            case SyncActionStatus.ErrorValidation:\n              return 'pages.external-api.errorStatus.validationError';\n            case SyncActionStatus.Canceled:\n              return 'pages.external-api.errorStatus.canceled';\n            case SyncActionStatus.ErrorUnknown:\n            default:\n              return 'pages.external-api.errorStatus.unknownError';\n          }\n        }\n      },\n      prepareSorting: createPrepareServersideSortingFunction(() => this.logFilter, 'status'),\n      filter: {\n        placeholderTk: 'globals.filter',\n        prepare: v => prepareServersideFiltering(this.logFilter, 'status' as VirtualFilterField, v, FilterOperationType.Eq),\n        options: [\n          { keyTk: 'pages.external-api.log.actionStatus.pending', value: SyncActionStatus.Pending },\n          { keyTk: 'pages.external-api.log.actionStatus.success', value: SyncActionStatus.Success },\n          { keyTk: 'pages.external-api.errorStatus.canceled', value: SyncActionStatus.Canceled },\n          { keyTk: 'pages.external-api.errorStatus.apiKeyRejected', value: SyncActionStatus.ErrorApiKeyRejected },\n          { keyTk: 'pages.external-api.errorStatus.nonBlocking', value: SyncActionStatus.ErrorNonblocking },\n          { keyTk: 'pages.external-api.errorStatus.serverError', value: SyncActionStatus.ErrorServerError },\n          { keyTk: 'pages.external-api.errorStatus.serverUnreachable', value: SyncActionStatus.ErrorServerUnreachable },\n          { keyTk: 'pages.external-api.errorStatus.timeout', value: SyncActionStatus.ErrorTimeout },\n          { keyTk: 'pages.external-api.errorStatus.unknownError', value: SyncActionStatus.ErrorUnknown },\n          { keyTk: 'pages.external-api.errorStatus.validationError', value: SyncActionStatus.ErrorValidation },\n        ]\n      }\n    },\n    {\n      id: 'data',\n      nameTk: 'globals.data',\n      cellViewModel: JsonCell,\n      cellOptions: {\n        json: log => log.data != null ? JSON.stringify(log.data) : '',\n      },\n      filter: {\n        placeholderTk: 'globals.filter',\n        prepare: v => prepareServersideFiltering(this.logFilter, 'data' as VirtualFilterField, v),\n      },\n    },\n    {\n      id: 'metadata',\n      nameTk: 'globals.metadata',\n      cellViewModel: JsonCell,\n      cellOptions: {\n        json: log => log.metadata != null ? JSON.stringify(log.metadata) : '',\n      },\n      filter: {\n        placeholderTk: 'globals.filter',\n        prepare: v => prepareServersideFiltering(this.logFilter, 'metadata' as VirtualFilterField, v),\n      },\n    },\n  ];\n\n  constructor(\n    private externalApiApiService: ExternalApiApiService,\n    private dateService: DateService,\n  ) { }\n\n  private async fetchTableData(\n    limit: number,\n    offset: number,\n  ): Promise<{ total: number; data: Array<IExternalApiSyncLogDto> }> {\n    this.logFilter.limit = limit;\n    this.logFilter.offset = offset;\n    const results = await this.externalApiApiService.getSyncLog(this.logFilter);\n    return { data: results.rows, total: results.count };\n  }\n}\n","import { autoinject } from 'aurelia-framework';\nimport { ExternalApiSyncStatus, IExternalApiTenantSyncStatusDto } from 'common/dto/external-api/external.api.interface';\nimport { LogUtils } from 'common/utils/LogUtils';\nimport { ExternalApiApiService } from '../../../services/api/ExternalApiApiService';\nimport { CustomDialogService } from '../../../services/CustomDialogService';\n\n@autoinject()\nexport class ExternalApiOverview {\n  private static readonly STATUS_POLL_INTERVAL_MS = 10000;\n\n  private ExternalApiSyncStatus = ExternalApiSyncStatus;\n\n  private status: IExternalApiTenantSyncStatusDto | null = null;\n\n  private timeout: number | undefined = undefined;\n\n  constructor(\n    private element: Element,\n    private api: ExternalApiApiService,\n    private customDialogService: CustomDialogService,\n  ) { }\n\n  protected attached(): void {\n    this.refreshStatus();\n  }\n\n  protected async detached(): Promise<void> {\n    window.clearTimeout(this.timeout);\n  }\n\n  private async createNewKey(): Promise<void> {\n    if(this.status?.sync === ExternalApiSyncStatus.Active) {\n      const confirmed = await this.customDialogService.confirmAction({\n        icon: { name: 'alert-triangle', color: 'var(--warning)' },\n        titleTk: 'pages.external-api.generateNewKey',\n        textTk: 'pages.external-api.generateNewKeyMessage',\n        confirmTk: 'globals.yes',\n      });\n\n      if(!confirmed) return;\n    }\n\n    await this.api.createKey();\n    this.refreshStatus();\n  }\n\n  private async refreshStatus(): Promise<void> {\n    window.clearTimeout(this.timeout);\n\n    // TODO KL-5979 status is currently refreshed by polling repeatedly. May be good enough.\n    try {\n      this.status = await this.api.getStatus();\n    } catch(e) {\n      LogUtils.error(`Failed to load external api status: ${e}`);\n    }\n\n    if(!this.element.isConnected) return;\n\n    this.timeout = window.setTimeout(() => this.refreshStatus(), ExternalApiOverview.STATUS_POLL_INTERVAL_MS);\n  }\n}\n","import { autoinject } from 'aurelia-framework';\nimport { IExternalApiSyncQueueEntryDto } from 'common/dto/external-api/external.api.interface';\nimport { ColumnSortDirection, FilterOperationType } from 'common/dto/filter/filter.enum';\nimport { IFilterDto } from 'common/dto/filter/filter.interface';\nimport { FinishedSyncActionStatus, SyncActionStatus, SyncActionType, VirtualSyncActionStatus } from 'common/enum/external-api/sync.enum';\nimport { Config } from 'common/fe-config/config';\nimport dayjs from 'dayjs';\nimport { CustomDialogService } from '../../../services/CustomDialogService';\nimport { DateService } from '../../../services/DateService';\nimport { ExternalApiApiService } from '../../../services/api/ExternalApiApiService';\nimport { ActionsCell } from '../custom-table/actions-cell/actions-cell';\nimport { CustomTableCell } from '../custom-table/custom-table-cell/custom-table-cell';\nimport {\n  VirtualFilterField,\n  createPrepareServersideSortingFunction,\n  deepPropertyString,\n  prepareServersideFiltering\n} from '../custom-table/custom-table-helpers';\nimport { IColumnDefinition } from '../custom-table/custom-table-interfaces';\nimport { JsonCell } from '../custom-table/json-cell/json-cell';\n\n@autoinject()\nexport class ExternalApiSyncQueue {\n  private syncQueueFilter: IFilterDto<IExternalApiSyncQueueEntryDto> = {\n    offset: 0,\n    limit: 10,\n    filter: [],\n    order: [{\n      field: 'createdAt',\n      dir: ColumnSortDirection.ASC,\n    }],\n  };\n  private tableRefreshVersion = 0;\n  private columnsSyncQueue: Array<IColumnDefinition<CustomTableCell<IExternalApiSyncQueueEntryDto> | JsonCell<IExternalApiSyncQueueEntryDto> | ActionsCell<IExternalApiSyncQueueEntryDto>>> = [\n    {\n      id: 'createdAt',\n      nameTk: 'globals.timestamp',\n      prepareSorting: createPrepareServersideSortingFunction(this.syncQueueFilter, 'createdAt'),\n      cellViewModel: CustomTableCell,\n      cellOptions: { transformer: e => this.dateService.formatDateTime(e.createdAt) },\n      filter: {\n        placeholderTk: 'globals.filter',\n        daterange: true,\n        prepare: v => {\n          const [start, end] = v.split('|');\n          const filterEndDate = end ? (dayjs(end).add(1, 'day')).toISOString() : '';\n          prepareServersideFiltering(this.syncQueueFilter, 'createdAt' as VirtualFilterField, start, FilterOperationType.Gt);\n          prepareServersideFiltering(this.syncQueueFilter, 'createdAt' as VirtualFilterField, filterEndDate, FilterOperationType.Lt);\n        },\n      },\n    },\n    {\n      id: 'lastAttemptTimestamp',\n      nameTk: 'pages.external-api.log.lastAttemptTimestamp',\n      prepareSorting: createPrepareServersideSortingFunction(this.syncQueueFilter, 'lastAttemptTimestamp'),\n      cellViewModel: CustomTableCell,\n      cellOptions: { transformer: e => this.dateService.formatDateTime(e.lastAttemptTimestamp) },\n      filter: {\n        placeholderTk: 'globals.filter',\n        daterange: true,\n        prepare: v => {\n          const [start, end] = v.split('|');\n          const filterEndDate = end ? (dayjs(end).add(1, 'day')).toISOString() : '';\n          prepareServersideFiltering(this.syncQueueFilter, 'lastAttemptTimestamp' as VirtualFilterField, start, FilterOperationType.Gt);\n          prepareServersideFiltering(this.syncQueueFilter, 'lastAttemptTimestamp' as VirtualFilterField, filterEndDate, FilterOperationType.Lt);\n        },\n      }\n    },\n    {\n      id: 'actionType',\n      nameTk: 'pages.external-api.log.actionType',\n      cellViewModel: CustomTableCell,\n      cellOptions: {\n        tk: entry => `pages.external-api.log.actionTypes.${entry.actionType}`\n      },\n      prepareSorting: createPrepareServersideSortingFunction(() => this.syncQueueFilter, 'actionType'),\n      filter: {\n        placeholderTk: 'globals.filter',\n        prepare: v => prepareServersideFiltering(this.syncQueueFilter, 'actionType' as VirtualFilterField, v, FilterOperationType.Eq),\n        options: [\n          { keyTk: 'pages.external-api.log.actionTypes.create', value: SyncActionType.Create },\n          { keyTk: 'pages.external-api.log.actionTypes.read', value: SyncActionType.Read },\n          { keyTk: 'pages.external-api.log.actionTypes.update', value: SyncActionType.Update },\n          { keyTk: 'pages.external-api.log.actionTypes.delete', value: SyncActionType.Delete },\n        ]\n      }\n    },\n    {\n      id: 'endpoint',\n      nameTk: 'pages.external-api.log.endpoint',\n      cellViewModel: CustomTableCell,\n      cellOptions: {\n        transformer: deepPropertyString('endpoint')\n      },\n      prepareSorting: createPrepareServersideSortingFunction(() => this.syncQueueFilter, 'endpoint'),\n      filter: {\n        placeholderTk: 'globals.filter',\n        prepare: v => prepareServersideFiltering(this.syncQueueFilter, 'endpoint', v),\n      },\n      wrap: true\n    },\n    {\n      id: 'status',\n      nameTk: 'globals.status',\n      cellViewModel: CustomTableCell,\n      cellOptions: {\n        tk: entry => {\n          switch(entry.status) {\n            case SyncActionStatus.Pending:\n            case SyncActionStatus.Success:\n              return `pages.external-api.log.actionStatus.${entry.status}`;\n            case SyncActionStatus.ErrorApiKeyRejected:\n              return 'pages.external-api.errorStatus.apiKeyRejected';\n            case SyncActionStatus.ErrorNonblocking:\n              return 'pages.external-api.errorStatus.nonBlocking';\n            case SyncActionStatus.ErrorServerError:\n              return 'pages.external-api.errorStatus.serverError';\n            case SyncActionStatus.ErrorServerUnreachable:\n              return 'pages.external-api.errorStatus.serverUnreachable';\n            case SyncActionStatus.ErrorTimeout:\n              return 'pages.external-api.errorStatus.timeout';\n            case SyncActionStatus.ErrorValidation:\n              return 'pages.external-api.errorStatus.validationError';\n            case SyncActionStatus.Canceled:\n              return 'pages.external-api.errorStatus.canceled';\n            case SyncActionStatus.ErrorUnknown:\n            default:\n              return 'pages.external-api.errorStatus.unknownError';\n          }\n        }\n      },\n      prepareSorting: createPrepareServersideSortingFunction(() => this.syncQueueFilter, 'status'),\n      filter: {\n        initialValue: VirtualSyncActionStatus.Todo,\n        placeholderTk: 'globals.filter',\n        prepare: v => prepareServersideFiltering(this.syncQueueFilter, 'status' as VirtualFilterField, v, FilterOperationType.Eq),\n        options: [\n          { keyTk: 'pages.external-api.log.actionStatus.todo', value: VirtualSyncActionStatus.Todo },\n          { keyTk: 'pages.external-api.log.actionStatus.done', value: VirtualSyncActionStatus.Done },\n          { keyTk: 'pages.external-api.log.actionStatus.pending', value: SyncActionStatus.Pending },\n          { keyTk: 'pages.external-api.log.actionStatus.success', value: SyncActionStatus.Success },\n          { keyTk: 'pages.external-api.errorStatus.canceled', value: SyncActionStatus.Canceled },\n          { keyTk: 'pages.external-api.errorStatus.apiKeyRejected', value: SyncActionStatus.ErrorApiKeyRejected },\n          { keyTk: 'pages.external-api.errorStatus.nonBlocking', value: SyncActionStatus.ErrorNonblocking },\n          { keyTk: 'pages.external-api.errorStatus.serverError', value: SyncActionStatus.ErrorServerError },\n          { keyTk: 'pages.external-api.errorStatus.serverUnreachable', value: SyncActionStatus.ErrorServerUnreachable },\n          { keyTk: 'pages.external-api.errorStatus.timeout', value: SyncActionStatus.ErrorTimeout },\n          { keyTk: 'pages.external-api.errorStatus.unknownError', value: SyncActionStatus.ErrorUnknown },\n          { keyTk: 'pages.external-api.errorStatus.validationError', value: SyncActionStatus.ErrorValidation },\n        ]\n      }\n    },\n    {\n      id: 'data',\n      nameTk: 'globals.data',\n      cellViewModel: JsonCell,\n      cellOptions: {\n        json: entry => entry.data != null ? JSON.stringify(entry.data) : '',\n      },\n      filter: {\n        placeholderTk: 'globals.filter',\n        prepare: v => prepareServersideFiltering(this.syncQueueFilter, 'data' as VirtualFilterField, v),\n      },\n    },\n    {\n      id: 'response',\n      nameTk: 'pages.external-api.log.response',\n      cellViewModel: JsonCell,\n      cellOptions: {\n        json: entry => entry.response != null ? JSON.stringify(entry.response) : '',\n      },\n      filter: {\n        placeholderTk: 'globals.filter',\n        prepare: v => prepareServersideFiltering(this.syncQueueFilter, 'response' as VirtualFilterField, v),\n      },\n    },\n    {\n      id: 'actions',\n      nameTk: '',\n      cellViewModel: ActionsCell,\n      shrink: true,\n      visible: e => Config().syncApi.allowCancel && e != null && !FinishedSyncActionStatus.includes(e.status),\n      cellOptions: {\n        entries: [\n          {\n            labelTk: 'globals.delete',\n            icon: 'fe-delete',\n            additionalClasses: 'text-danger',\n            clickCallback: e => { this.deleteSyncQueueEntry(e); }\n          },\n        ]\n      }\n    }\n  ];\n\n  constructor(\n    private externalApiApiService: ExternalApiApiService,\n    private dateService: DateService,\n    private customDialogService: CustomDialogService,\n  ) { }\n\n  private async fetchTableData(\n    limit: number,\n    offset: number,\n  ): Promise<{ total: number; data: Array<IExternalApiSyncQueueEntryDto> }> {\n    this.syncQueueFilter.limit = limit;\n    this.syncQueueFilter.offset = offset;\n    const results = await this.externalApiApiService.getSyncQueue(this.syncQueueFilter);\n    return { data: results.rows, total: results.count };\n  }\n\n  private async deleteSyncQueueEntry(item: IExternalApiSyncQueueEntryDto): Promise<void> {\n    if(!await this.customDialogService.confirmDeletion()) return;\n\n    await this.externalApiApiService.deleteSyncQueueEntry(item.id);\n    this.tableRefreshVersion++;\n  }\n}\n"],"names":[],"sourceRoot":""}