{"version":3,"sources":["webpack:///./src/pages/dashboard-program-edit/batch-field-edit/batch-field-edit.ts","webpack:///./src/pages/dashboard-program-edit/batch-field-edit/batch-field-edit.html","webpack:///./src/pages/dashboard-program-edit/dashboard-program-edit.ts","webpack:///./src/pages/dashboard-program-edit/dashboard-program-edit.html","webpack:///./src/pages/dashboard-program-edit/routes/assets/asset-type-edit.ts","webpack:///./src/pages/dashboard-program-edit/routes/assets/asset-type-edit.html","webpack:///./src/pages/dashboard-program-edit/routes/assets/assets-list.ts","webpack:///./src/pages/dashboard-program-edit/routes/assets/assets-list.html","webpack:///./src/pages/dashboard-program-edit/routes/configs-edit.ts","webpack:///./src/pages/dashboard-program-edit/routes/configs-edit.html","webpack:///./src/pages/dashboard-program-edit/routes/file-folders-edit.ts","webpack:///./src/pages/dashboard-program-edit/routes/file-folders-edit.html","webpack:///./src/pages/dashboard-program-edit/routes/job-detail.ts","webpack:///./src/pages/dashboard-program-edit/routes/job-detail.html","webpack:///./src/pages/dashboard-program-edit/routes/map-edit/map-edit.ts","webpack:///./src/pages/dashboard-program-edit/routes/map-edit/map-edit.html","webpack:///./src/pages/dashboard-program-edit/routes/program-edit.ts","webpack:///./src/pages/dashboard-program-edit/routes/program-edit-organizations/program-edit-organizations.ts","webpack:///./src/pages/dashboard-program-edit/routes/program-edit-organizations/program-edit-organizations.html","webpack:///./src/pages/dashboard-program-edit/routes/program-edit.html","webpack:///./src/pages/dashboard-program-edit/routes/projects-edit.ts","webpack:///./src/pages/dashboard-program-edit/routes/projects-edit.html","webpack:///./src/pages/dashboard-program-edit/routes/share-data.ts","webpack:///./src/pages/dashboard-program-edit/routes/share-data.html","webpack:///./src/pages/dashboard-program-edit/routes/surveys-edit.ts","webpack:///./src/pages/dashboard-program-edit/routes/surveys-edit.html","webpack:///./src/pages/dashboard-program-edit/routes/surveys-list.ts","webpack:///./src/pages/dashboard-program-edit/routes/surveys-list-add-geojson/surveys-list-add-geojson.ts","webpack:///./src/pages/dashboard-program-edit/routes/surveys-list-add-geojson/surveys-list-add-geojson.html","webpack:///./src/pages/dashboard-program-edit/routes/surveys-list-template-dialog/surveys-list-template-dialog.ts","webpack:///./src/pages/dashboard-program-edit/routes/surveys-list-template-dialog/surveys-list-template-dialog.html","webpack:///./src/pages/dashboard-program-edit/routes/surveys-list.html","webpack:///./src/pages/dashboard-program-edit/routes/users-edit.ts","webpack:///./src/pages/dashboard-program-edit/routes/users-edit.html"],"names":["BatchFieldEdit","dialogController","alerts","flatrows","rows","selection","column","undefined","value","data","this","customFieldSelection","model","preserveParent","arrays","forEach","field","flatField","name","label","type","path","visibility","fieldSelection","includes","push","selectAll","row","checked","hideRepeatedAndSystemFields","col","sort","a","b","nameA","toString","toUpperCase","nameB","filter","list","length","create","level","dismissable","applyAllEdits","ok","removePath","cancel","item","fields","obj","parent","child","newParent","concat","getPath","find","flatrow","edit","module","exports","DashboardProgramEdit","validationFactory","api","dialogService","recentPrograms","super","dirtyProps","handleMediaQuery","evt","matches","isMobile","validationController","createForCurrentScope","mediaQuery","window","matchMedia","addEventListener","params","id","program","replace","config","router","programId","parseInt","orgId","auth","me","organizationId","programs","get","query","$eager","then","result","files","catch","e","managementOrganizationId","settings","map","route","moduleId","title","fallbackRoute","refresh","open","viewModel","whenClosed","wasCancelled","Error","remove","navigate","message","keepCache","destroy","Object","assign","updateClones","manageActivity","getThumbnail","events","eventEmitter","event","fn","AssetTypeEdit","validationControllerFactory","alertService","geometryTypes","assetId","asset","programAssetTypes","program_id","assetType","finish","validate","valid","patch","navigateToRoute","AssetsList","updateConfigs","$sort","assets","ConfigsEdit","appConfig","isModified","showAdvancedEditor","configId","programConfigs","defaults","getDefaultsForStoreType","populateMapLayers","layerDefaults","projectFeatures","geometryType","visible","source","url","baseUrl","API_HOST","typeId","serviceType","options","projectSchema","surveys","s","surveySchema","assetTypes","assetSchema","service","JSON","parse","stringify","updateMapQuery","navigateBack","dashboardsToUpdate","dashboard","items","flatMap","mapOptions","layers","some","layer","Promise","all","variableName","newText","el","textField","querySelector","start","end","selectionStart","selectionEnd","setRangeText","selectedVariableText","FileFoldersEdit","fileFolders","JobDetail","webhookId","jobId","updateJob","clearTimer","retryTimeout","loading","jobs","$select","job","status","scheduleTimer","finally","timer","setInterval","clearInterval","MapEdit","mapConfig","configs","description","scopes","ProgramEdit","dialogs","tourDriver","basicFields","getProgramImageName","f","fileName","tabs","collect","projects","thumbnailUrl","userLocation","autoEnabled","organizations","$limit","orgs","orgName","org","setTour","$event","isProcessing","fileId","detail","created","width","$sync","replaceThumbnail","output","orgUpdated","programUsersRoles","role","program_org_id","updateProgramUserRoles","ProgramEditOrganizations","confirmation","logger","getLogger","ProjectEdit","projectQuery","currentProjectFilters","startsWith","filterProperties","debug","ShareData","serviceTable","survey","survey_type","SurveysEdit","signaler","surveyOptions","surveyId","updateSurvey","programSurveys","resolve","active","shareToPublic","handleAttachmentsField","updateSurveys","attachmentsField","unshift","signal","$path","file","test","fileParts","split","survey_id","$url","formFields","formChoices","sheet","schema","nonEmptyFields","metadata","programFolderExists","folder","addAttachments","refreshSurveyFields","savedSurvey","surveyWithActions","newSurvey","updateProgramFolders","index","action","actions","allowOnAll","inline","editAction","addAction","actionData","splice","removeAction","GenerateCSV","GeneratePDF","SaveFile","Query","Populate","GenerateKoboURL","EditDFPForm","scope","join","SurveysList","actionService","element","getFileName","fileType","getFileType","addFileToList","eventDetail","publishForm","updateFiles","fileExt","pop","t","template","paths","promises","charAt","slice","results","reduce","searchFiles","table","target","dispatchEvent","removed","navigator","clipboard","writeText","timeout","filteredFiles","searchString","toLowerCase","Element","SurveysListAddGeojson","mappedField","getGeoJSONFields","surveyFields","blob","uri","geojsonData","text","parseJSON","i","features","geometry","coordinates","isMapped","geojsonField","surveyField","throttle","limit","interval","pending","metadataObj","buildMetadataObj","username","fullname","throttled","progress","toFixed","formSubmissions","instance_id","geom","attachments","feature","current","segment","indexOf","properties","SurveysListTemplateDialog","bodyText","UsersEdit","currentSortColumn","columnList","updateAppRoles","updateProgram","organization","license_limit","updateLicenseCount","updateUsers","appRoles","roles","$contains","$joinRelation","licenseCount","array","user","licenseExempt","findIndex","v","user_id","licenseRatio","licenseStatusClass","usersLoading","accessibleOrgs","partner_orgs","$in","users","u","orgList","Array","from","Set","newUserList","appRole","role_id","org_name","role_name","valueA","valueB","Date","updatedAt","getTime","newRole","r","roleToUpdate","roleToAdd","userId","roleToRemove","$or","$ilike","filterId","activeColumns","option"],"mappings":"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","file":"app~a7f36ad7.bd77b3093642c4f8bd45.chunk.js","sourcesContent":["import { Field } from '@wsb_dev/datafi-shared/lib/types';\nimport { DialogController } from 'aurelia-dialog';\nimport { autoinject } from 'aurelia-framework';\nimport { flattenFields } from '@wsb_dev/datafi-shared/lib/util/surveys/flattenFields';\nimport { AlertService } from 'services/util/Alert';\n\nexport interface editSelection {\n    column: string,\n    value: boolean\n}\n@autoinject\n\nexport class BatchFieldEdit {\n\n    flatrows: Field[] = [];\n    rows: Field[] = [];\n    sort: number;\n    selection = {\n        column: undefined,\n        value: undefined,\n    } as editSelection;\n    customFieldSelection: boolean;\n\n    constructor(\n        private dialogController: DialogController,\n        private alerts: AlertService,\n    ) { }\n\n    activate(data: { model: Field[], fieldSelection?: Array<string>, customFieldSelection?: boolean }) {\n        this.customFieldSelection = data?.customFieldSelection;\n        this.rows = data.model;\n        flattenFields(data.model, null, { preserveParent: true, arrays: true }).forEach((field) => {\n            const flatField = {\n                name: field.name,\n                label: field.label,\n                type: field.type,\n                path: field.path,\n                ...field.visibility,\n            };\n\n            if (data?.fieldSelection) {\n                if (data?.fieldSelection.includes(field.path)) {\n                    flatField['list'] = true;\n                    flatField['edit'] = true;\n                    flatField['filter'] = true;\n                } else {\n                    flatField['list'] = false;\n                    flatField['edit'] = false;\n                    flatField['filter'] = false;\n                }\n            }\n\n            this.flatrows.push(flatField);\n        });\n    }\n\n    onSelectionChanged(selectAll: boolean) {\n        this.flatrows.forEach((row) => {\n            selectAll ? row.checked = true : row.checked = false;\n        });\n        this.flatrows = [...this.flatrows];\n    }\n\n    updateValue(hideRepeatedAndSystemFields?: boolean) {\n        if (hideRepeatedAndSystemFields) {\n            this.flatrows.forEach((row) => {\n                if (!row.path.includes('metadata.')) {\n                    row['list'] = false;\n                    row['edit'] = false;\n                    row['filter'] = false;\n                }\n            });\n        } else {\n            if (this.selection.value === undefined) {\n                return;\n            }\n\n            this.flatrows.forEach((row) => {\n                if (row.checked) {\n                    row[this.selection.column] = this.selection.value;\n                }\n            });\n        }\n\n        this.flatrows = [...this.flatrows];\n    }\n\n    handleSort(col: string): void {\n        this.sort === 1 ? this.sort = -1 : this.sort = 1;\n        this.flatrows.sort(\n            (a: { name: string }, b: { name: string }) => {\n                const nameA = (a[col]).toString().toUpperCase();\n                const nameB = (b[col]).toString().toUpperCase();\n\n                if (this.sort === 1) {\n                    // asc, arrow up\n                    if (nameA < nameB) { return -1; }\n                    if (nameA > nameB) { return 1; }\n                    return 0;\n                } else {\n                    // desc, arrow down\n                    if (nameA > nameB) { return -1; }\n                    if (nameA < nameB) { return 1; }\n                    return 0;\n                }\n            },\n        );\n    }\n\n    submit() {\n        if (this.flatrows.filter((row) => row.list).length > 15 && this.customFieldSelection) {\n            return this.alerts.create({\n                label: 'You can only select up to 15 fields',\n                level: 'error',\n                dismissable: true,\n            });\n        }\n        this.applyAllEdits(this.rows, '', '');\n        this.dialogController.ok(this.rows);\n    }\n\n    cancel() {\n        this.removePath(this.rows);\n        this.dialogController.cancel(this.rows);\n    }\n\n    removePath(rows) {\n        rows.forEach((item) => {\n            if (item.type === 'object') {\n                delete item.path;\n                this.removePath(item.fields);\n            } else if (item.type === 'array') {\n                delete item.path;\n                this.removePath(item.fields);\n            }\n            delete item.path;\n        });\n    }\n\n    applyAllEdits(obj: Field[], parent: string, child: string) {\n        obj.forEach((item) => {\n            child = item.name;\n            if (item.type === 'object') {\n                delete item.path;\n                const newParent = parent.concat(item.name + '.');\n                this.applyAllEdits(item.fields, newParent, child);\n            } else if ('name' in item) {\n                const getPath = this.flatrows.find((flatrow) =>\n                    flatrow.path === parent.concat(child) ||\n                    (parent.includes('metadata') && flatrow.path === child),\n                );\n                if (getPath) {\n                    item.visibility.filter = getPath.filter;\n                    item.visibility.list = getPath.list;\n                    item.visibility.edit = getPath.edit;\n                }\n                if (item.type === 'array' && item.path !== 'attachments') {\n                    const newParent = parent.concat(`${item.name}.`);\n                    this.applyAllEdits(item.fields, newParent, child);\n                }\n            }\n        });\n    }\n}\n","// Module\nvar code = \"<template> <ux-dialog> <ux-dialog-header> <h3 class=\\\"align-header\\\">Batch Edit</h3> <button class=\\\"button--color--secondary float-right\\\" icon=\\\"close\\\" mdc-icon-button click.trigger=\\\"dialogController.cancel()\\\"></button> </ux-dialog-header> <ux-dialog-body> <div class=\\\"mb-7\\\" if.bind=\\\"rows.length\\\"> <mdc-select label=\\\"Select a Column\\\" value.bind=\\\"selection.column\\\" if.bind=\\\"!selectedRows\\\"> <mdc-list> <mdc-list-item value=\\\"list\\\">Table</mdc-list-item> <mdc-list-item if.bind=\\\"!customFieldSelection\\\" value=\\\"filter\\\">Filter</mdc-list-item> </mdc-list> </mdc-select> <mdc-select value.bind=\\\"selection.value\\\" label=\\\"Update selection to\\\" class=\\\"m-2\\\" disabled.bind=\\\"!selection.column\\\"> <mdc-list> <mdc-list-item value.bind=\\\"true\\\">Yes</mdc-list-item> <mdc-list-item value.bind=\\\"false\\\">No</mdc-list-item> </mdc-list> </mdc-select> <button disabled.bind=\\\"selection.value == undefined\\\" class=\\\"button--color--background\\\" mdc-button raised click.trigger=\\\"updateValue()\\\">Update Rows</button> </div> <div class=\\\"mb-7\\\" if.bind=\\\"rows.length\\\"> <span class=\\\"mr-2\\\">Hide all repeated groups and system fields</span><button class=\\\"button--color--grey--primary\\\" mdc-button click.trigger=\\\"updateValue(true)\\\">Apply</button> </div> <mdc-data-table if.bind=\\\"rows.length\\\" class=\\\"w-100\\\" style=\\\"height:calc(65vh - 200px)\\\" mdcdatatable:selectedall.delegate=\\\"onSelectionChanged(true)\\\" mdcdatatable:unselectedall.delegate=\\\"onSelectionChanged(false)\\\" sticky-header> <table> <thead> <th> <mdc-checkbox></mdc-checkbox> </th> <th>Label <button class=\\\"mdc-icon-button material-icons mdc-data-table__sort-icon-button\\\" click.delegate=\\\"handleSort('label')\\\" aria-label=\\\"Sort Files\\\"> <mdc-icon if.bind=\\\"sort === 1\\\">arrow_upward</mdc-icon> <mdc-icon else>arrow_downward</mdc-icon> </button> </th> <th>Table <button class=\\\"mdc-icon-button material-icons mdc-data-table__sort-icon-button\\\" click.delegate=\\\"handleSort('list')\\\" aria-label=\\\"Sort Files\\\"> <mdc-icon if.bind=\\\"sort === 1\\\">arrow_upward</mdc-icon> <mdc-icon else>arrow_downward</mdc-icon> </button> </th> <th if.bind=\\\"!customFieldSelection\\\">Filter <button class=\\\"mdc-icon-button material-icons mdc-data-table__sort-icon-button\\\" click.delegate=\\\"handleSort('filter')\\\" aria-label=\\\"Sort Files\\\"> <mdc-icon if.bind=\\\"sort === 1\\\">arrow_upward</mdc-icon> <mdc-icon else>arrow_downward</mdc-icon> </button> </th> <th>Type <button class=\\\"mdc-icon-button material-icons mdc-data-table__sort-icon-button\\\" click.delegate=\\\"handleSort('type')\\\" aria-label=\\\"Sort Files\\\"> <mdc-icon if.bind=\\\"sort === 1\\\">arrow_upward</mdc-icon> <mdc-icon else>arrow_downward</mdc-icon> </button> </th> <th>Path <button class=\\\"mdc-icon-button material-icons mdc-data-table__sort-icon-button\\\" click.delegate=\\\"handleSort('path')\\\" aria-label=\\\"Sort Files\\\"> <mdc-icon if.bind=\\\"sort === 1\\\">arrow_upward</mdc-icon> <mdc-icon else>arrow_downward</mdc-icon> </button> </th> </thead> <tbody> <tr mdc-data-table-row repeat.for=\\\"row of flatrows\\\"> <td> <mdc-checkbox checked.bind=\\\"row.checked\\\"></mdc-checkbox> </td> <td class=\\\"mw-400\\\">${row.label}</td> <td> <mdc-form-field> <button mdc-switch selected.bind=\\\"row.list\\\"></button> </mdc-form-field> </td> <td if.bind=\\\"!customFieldSelection\\\"> <mdc-form-field if.bind=\\\"row.type !== 'array'\\\"> <button mdc-switch selected.bind=\\\"row.filter\\\"></button> </mdc-form-field> </td> <td>${row.type}</td> <td>${row.path}</td> </tr> </tbody> </table> </mdc-data-table> </ux-dialog-body> <ux-dialog-footer> <button class=\\\"button--color--secondary float-left\\\" mdc-button click.trigger=\\\"cancel()\\\">Cancel</button> <button attach-focus class=\\\"button--raised--secondary\\\" mdc-button raised click.trigger=\\\"submit()\\\">Save all Edits</button> </ux-dialog-footer> <div class=\\\"mdc-dialog__scrim\\\"></div> </ux-dialog> </template> \";\n// Exports\nmodule.exports = code;","import { autoinject, bindable } from 'aurelia-framework';\nimport { PLATFORM } from 'aurelia-pal';\nimport { Router, RouterConfiguration, Redirect, activationStrategy, RoutableComponentDetermineActivationStrategy } from 'aurelia-router';\nimport { ValidationController, ValidationControllerFactory } from 'aurelia-validation';\nimport { DatafiProAPI } from '../../services/api/DatafiProAPI';\nimport { AlertService } from '../../services/util/Alert';\nimport { Program } from '../../types/Program';\nimport { debounced } from '../../util/decorators/debounced';\nimport { ProgramDelete } from './../../components/programs/program-delete/program-delete';\nimport { DialogService } from 'aurelia-dialog';\nimport { DirtyChecker } from '../../types/DirtyChecker';\nimport { subscribe } from '../../util/decorators/subscribe';\nimport { ProgramActivity, RecentPrograms } from '../../services/util/RecentPrograms';\nimport { ensureNumber } from '../../util/numbers/ensureNumber';\nimport { userHasPermission } from '@wsb_dev/datafi-shared/lib/util/users/userHasPermission';\n\n@autoinject\n@subscribe({\n    events: [\n        { eventEmitter: 'api.programs', event: 'patched', fn: 'refresh' },\n    ],\n})\nexport class DashboardProgramEdit extends DirtyChecker implements RoutableComponentDetermineActivationStrategy {\n    public dirtyProps: string[] = ['program']\n    validationController: ValidationController;\n    router: Router;\n    program: Program;\n    sort: number;\n    programId: number;\n    @bindable isMobile: boolean;\n    mediaQuery: MediaQueryList;\n\n    constructor(\n        private validationFactory: ValidationControllerFactory,\n        private api: DatafiProAPI,\n        private alerts: AlertService,\n        private dialogService: DialogService,\n        private recentPrograms: RecentPrograms,\n    ) {\n        super();\n        this.validationController = this.validationFactory.createForCurrentScope();\n        this.mediaQuery = window.matchMedia('(max-width: 600px)');\n        this.handleMediaQuery(this.mediaQuery);\n\n        this.mediaQuery.addEventListener('change', this.handleMediaQuery);\n    }\n\n    determineActivationStrategy(params) {\n        if (ensureNumber(params.id) !== this.program.id) {\n            return activationStrategy.replace;\n        }\n    }\n\n    async configureRouter(config: RouterConfiguration, router: Router, params) {\n        const programId = parseInt(params.id, 10);\n        const orgId = userHasPermission(this.api.auth.me, '*', '*') ? 0 : this.api.auth.me?.organizationId;\n        this.program = programId ?\n            await this.api.programs.get(programId, {\n                query: { $eager: '[assetTypes, configs, surveys, roles.role]' },\n            })\n                .then((result) => new Program(result, this.api.files))\n                .catch((e) => undefined) :\n            new Program({ managementOrganizationId: orgId }, this.api.files);\n\n        const settings = { programId: params.id, program: this.program };\n\n        config.map([\n            { name: 'program-edit', route: '', moduleId: PLATFORM.moduleName('pages/dashboard-program-edit/routes/program-edit'), settings },\n            { name: 'projects-edit', route: 'projects-edit', moduleId: PLATFORM.moduleName('pages/dashboard-program-edit/routes/projects-edit'), settings },\n            { name: 'file-folders-edit', route: 'file-folders-edit', moduleId: PLATFORM.moduleName('pages/dashboard-program-edit/routes/file-folders-edit'), settings },\n\n            { name: 'surveys-list', route: 'surveys/list', moduleId: PLATFORM.moduleName('pages/dashboard-program-edit/routes/surveys-list'), settings },\n            { name: 'surveys-edit', route: 'surveys/:surveyId', moduleId: PLATFORM.moduleName('pages/dashboard-program-edit/routes/surveys-edit'), settings },\n\n            { name: 'assets-list', route: 'assets/list', moduleId: PLATFORM.moduleName('pages/dashboard-program-edit/routes/assets/assets-list'), settings },\n            { name: 'assets-edit', route: 'assets/edit/:assetId', moduleId: PLATFORM.moduleName('pages/dashboard-program-edit/routes/assets/asset-type-edit'), settings },\n\n            { name: 'users-edit', route: 'users', moduleId: PLATFORM.moduleName('pages/dashboard-program-edit/routes/users-edit'), settings },\n\n            { name: 'map-edit', route: 'map', moduleId: PLATFORM.moduleName('pages/dashboard-program-edit/routes/map-edit/map-edit'), settings },\n\n            // { name: 'auth-edit', route: 'auth-edit', moduleId: PLATFORM.moduleName('pages/dashboard-program-edit/routes/auth-edit'), settings },\n\n            { name: 'share-data', route: 'share-data', moduleId: PLATFORM.moduleName('pages/dashboard-program-edit/routes/share-data'), settings },\n\n            { name: 'webhook-list', route: ['webhook/list'], moduleId: PLATFORM.moduleName('pages/dashboard-program-edit/routes/webhook-list'), title: 'Webhooks', settings },\n            { name: 'webhook-create', route: ['webhook/create'], moduleId: PLATFORM.moduleName('pages/dashboard-program-edit/routes/webhook-edit'), title: 'Create Webhook', settings },\n            { name: 'webhook-edit', route: ['webhook/edit/:webhookId'], moduleId: PLATFORM.moduleName('pages/dashboard-program-edit/routes/webhook-edit'), title: 'Create Webhook', settings },\n            { name: 'webhook-detail', route: 'webhook/:webhookId', moduleId: PLATFORM.moduleName('pages/dashboard-program-edit/routes/webhook-detail'), title: 'Webhook Details', settings },\n            { name: 'webhook-job-detail', route: 'webhook/:webhookId/job/:jobId', moduleId: PLATFORM.moduleName('pages/dashboard-program-edit/routes/job-detail'), title: 'Webhook Job Details', settings },\n\n        ]);\n\n        config.fallbackRoute('dashboard-program-edit');\n\n        this.router = router;\n    }\n\n    canActivate(params: any) {\n        const hasPermission = parseInt(params.id, 10) === 0 ?\n            userHasPermission(this.api.auth.me, 'api/v1/programs', 'create') :\n            userHasPermission(this.api.auth.me, 'api/v1/programs', 'patch', parseInt(params.id, 10));\n        if (hasPermission) {\n            return true;\n        }\n        return new Redirect('/');\n    }\n\n    async activate(params: any) {\n        this.sort = -1;\n        this.programId = parseInt(params.id, 10);\n        this.refresh(true);\n    }\n\n    delete(): Promise<void> {\n        return this.dialogService.open({\n            model: this.program,\n            viewModel: ProgramDelete,\n        }).whenClosed((result) => {\n            if (result.wasCancelled) {\n                throw new Error('Program was not deleted');\n            }\n        })\n            .then(() => {\n                return this.api.programs.remove(this.program.id)\n                    .then(() => {\n                        this.alerts.create({\n                            label: 'Program Deleted',\n                            level: 'success',\n                            dismissable: true,\n                        });\n                        this.router.navigate('/');\n                    })\n                    .catch((e) => this.alerts.create({\n                        label: e.message,\n                        level: 'error',\n                        dismissable: true,\n                    }));\n            });\n    }\n\n    @debounced(500)\n    async refresh(keepCache?: boolean): Promise<void> {\n\n        if (!keepCache) {\n            if (this.program) {\n                this.program.destroy();\n            } else {\n                this.program = new Program({}, this.api.files);\n            }\n        }\n\n        const orgId = userHasPermission(this.api.auth.me, '*', '*') ? 0 : this.api.auth.me.organizationId;\n\n        const data = this.programId ?\n            await this.api.programs.get(this.programId, {\n                query: { $eager: '[assetTypes, configs, surveys, roles.role]' },\n            })\n                .then((result) => new Program(result, this.api.files))\n                .catch((e) => undefined) :\n            new Program({ managementOrganizationId: orgId }, this.api.files);\n\n        Object.assign(this.program, data);\n        this.updateClones();\n        if (this.programId !== 0) { this.recentPrograms.manageActivity({ id: this.programId, title: this.program.title, managementOrganizationId: this.program.managementOrganizationId } as ProgramActivity); }\n        this.program.getThumbnail();\n    }\n\n    handleMediaQuery = (evt) => {\n        return evt.matches ? this.isMobile = true : this.isMobile = false;\n    }\n}\n","// Module\nvar code = \"<template> <require from=\\\"../../components/dashboard-layout/dashboard-layout\\\"></require> <dashboard-layout> <div slot=\\\"img\\\"> <div if.bind=\\\"program._blobs.thumbnail.url\\\" class=\\\"cover-photo bg-image\\\" css=\\\"background-image:url(${program._blobs.thumbnail.url});\\\"></div> <div class=\\\"text-center\\\" else> <mdc-icon class=\\\"card__image icon-xxlg mt-4 mr-2\\\">image</mdc-icon> </div> </div> <span slot=\\\"subtitle\\\">${program.title}</span> <template replace-part=\\\"sidebar\\\"> <mdc-list class=\\\"list-item--color--default\\\"> <a activated tabindex=\\\"0\\\" route-href=\\\"route: program-edit\\\" mdc-list-item> <mdc-icon mdc-list-item-leading>assignment</mdc-icon><span class=\\\"text-small\\\">GENERAL</span> </a> <span if.bind=\\\"programId\\\"> <a tabindex=\\\"1\\\" route-href=\\\"route: projects-edit\\\" mdc-list-item> <mdc-icon mdc-list-item-leading>place</mdc-icon><span class=\\\"text-small\\\">PROJECTS</span> </a> <a tabindex=\\\"1\\\" route-href=\\\"route: file-folders-edit\\\" mdc-list-item> <mdc-icon mdc-list-item-leading>folder</mdc-icon><span class=\\\"text-small\\\">FILE FOLDERS</span> </a> <a tabindex=\\\"2\\\" route-href=\\\"route: surveys-list\\\" mdc-list-item> <mdc-icon mdc-list-item-leading>add_location</mdc-icon><span class=\\\"text-small\\\">SURVEYS</span> </a> <a tabindex=\\\"2\\\" route-href=\\\"route: assets-list\\\" mdc-list-item if.bind=\\\"api.auth.me | hasPermission:'*':'*'\\\"> <mdc-icon mdc-list-item-leading>insights</mdc-icon><span class=\\\"text-small\\\">ASSETS</span> </a> <a tabindex=\\\"3\\\" route-href=\\\"route: webhook-list\\\" mdc-list-item if.bind=\\\"api.auth.me | hasPermission:'*':'*'\\\"> <mdc-icon mdc-list-item-leading>webhook</mdc-icon><span class=\\\"text-small\\\">WEBHOOKS</span> <a tabindex=\\\"5\\\" route-href=\\\"route: users-edit\\\" mdc-list-item> <mdc-icon mdc-list-item-leading>group</mdc-icon><span class=\\\"text-small\\\">USERS</span> </a> <a tabindex=\\\"6\\\" route-href=\\\"route: map-edit\\\" mdc-list-item> <mdc-icon mdc-list-item-leading>map</mdc-icon><span class=\\\"text-small\\\">MAP</span> </a> <a tabindex=\\\"8\\\" route-href=\\\"route: share-data\\\" mdc-list-item> <mdc-icon mdc-list-item-leading>public</mdc-icon><span class=\\\"text-small\\\">SHARE DATA</span> </a> </a></span> <div class=\\\"divider\\\"></div> <a if.bind=\\\"programId\\\" tabindex=\\\"11\\\" class=\\\"list-item--color--danger\\\" click.delegate=\\\"delete()\\\" mdc-list-item> <mdc-icon mdc-list-item-leading>delete</mdc-icon><span class=\\\"text-small\\\">DELETE PROGRAM</span> </a> </mdc-list> </template> <div if.bind=\\\"isMobile\\\" slot=\\\"sidebar-mobile\\\"> <mdc-list> <mdc-list> <a activated tabindex=\\\"0\\\" route-href=\\\"route: program-edit\\\" mdc-list-item> <mdc-icon mdc-list-item-leading>assignment</mdc-icon><span class=\\\"text-small\\\">GENERAL</span> </a> <span if.bind=\\\"programId\\\"> <a tabindex=\\\"1\\\" route-href=\\\"route: projects-edit\\\" mdc-list-item> <mdc-icon mdc-list-item-leading>place</mdc-icon><span class=\\\"text-small\\\">PROJECTS</span> </a> <a tabindex=\\\"1\\\" route-href=\\\"route: file-folders-edit\\\" mdc-list-item> <mdc-icon mdc-list-item-leading>folder</mdc-icon><span class=\\\"text-small\\\">FILE FOLDERS</span> </a> <a tabindex=\\\"2\\\" route-href=\\\"route: surveys-list\\\" mdc-list-item> <mdc-icon mdc-list-item-leading>add_location</mdc-icon><span class=\\\"text-small\\\">SURVEYS</span> </a> <a tabindex=\\\"3\\\" route-href=\\\"route: webhook-list\\\" mdc-list-item if.bind=\\\"api.auth.me | hasPermission:'*':'*'\\\"> <mdc-icon mdc-list-item-leading>webhook</mdc-icon><span class=\\\"text-small\\\">WEBHOOKS</span> </a> <a tabindex=\\\"5\\\" route-href=\\\"route: users-edit\\\" mdc-list-item> <mdc-icon mdc-list-item-leading>group</mdc-icon><span class=\\\"text-small\\\">USERS</span> </a> <a tabindex=\\\"6\\\" route-href=\\\"route: map-edit\\\" mdc-list-item> <mdc-icon mdc-list-item-leading>map</mdc-icon><span class=\\\"text-small\\\">MAP</span> </a> <a tabindex=\\\"8\\\" route-href=\\\"route: share-data\\\" mdc-list-item> <mdc-icon mdc-list-item-leading>public</mdc-icon><span class=\\\"text-small\\\">SHARE DATA</span> </a> </span> <div class=\\\"divider\\\"></div> <a if.bind=\\\"programId\\\" tabindex=\\\"11\\\" class=\\\"list-item--color--danger\\\" click.delegate=\\\"delete()\\\" mdc-list-item> <mdc-icon class=\\\"\\\" mdc-list-item-leading>delete</mdc-icon><span class=\\\"text-small\\\">DELETE PROGRAM</span> </a> </mdc-list> </mdc-list> </div> <div slot=\\\"main\\\" class=\\\"p-2 w-100 d-flex h-fit min-h-100\\\"> <router-view class=\\\"d-flex flex-column\\\"></router-view> </div> </dashboard-layout> </template> \";\n// Exports\nmodule.exports = code;","import { AssetGeometryType, geometryTypes } from '@wsb_dev/datafi-shared/lib/types/ProgramAsset';\nimport { ProgramAssetType } from '@wsb_dev/datafi-shared/lib/types/ProgramAssetType';\nimport { autoinject } from 'aurelia-dependency-injection';\nimport { Router, Redirect } from 'aurelia-router';\nimport { ValidationController, ValidationControllerFactory } from 'aurelia-validation';\nimport { DatafiProAPI } from '../../../../services/api/DatafiProAPI';\nimport { AlertService } from '../../../../services/util/Alert';\nimport { ValidatedProgramAssetType } from '../../../../types/ProgramAssetType';\nimport { ensureNumber } from '../../../../util/numbers/ensureNumber';\nimport { userHasPermission } from '@wsb_dev/datafi-shared/lib/util/users/userHasPermission';\n\n@autoinject\nexport class AssetTypeEdit {\n    assetTypes: ProgramAssetType[];\n    validationController: ValidationController;\n    assetType: ValidatedProgramAssetType;\n    assetId: number;\n    programId: number;\n\n    geometryTypes: AssetGeometryType[] = geometryTypes;\n\n    constructor(\n        private api: DatafiProAPI,\n        private validationControllerFactory: ValidationControllerFactory,\n        private alertService: AlertService,\n        private router: Router,\n    ) { }\n\n    canActivate() {\n        if (userHasPermission(this.api.auth.me, '*', '*')) {\n            return true;\n        }\n        return new Redirect('/');\n    }\n\n    async activate(params, config) {\n        this.assetId = ensureNumber(params.assetId);\n        this.programId = ensureNumber(config.settings.programId);\n\n        const asset = this.assetId ? await this.api.programAssetTypes.get(this.assetId, { query: { program_id: this.programId } }) : { program_id: this.programId };\n        this.assetType = new ValidatedProgramAssetType(asset);\n        this.geometryTypes = geometryTypes;\n        this.validationController = this.validationControllerFactory.createForCurrentScope();\n    }\n\n    submit(finish?: boolean) {\n        const assetType = this.assetType;\n        return this.validationController.validate()\n            .then((result) => {\n                if (result.valid) {\n                    if (assetType.id) {\n                        return this.api.programAssetTypes.patch(assetType.id, assetType);\n                    } else {\n                        return this.api.programAssetTypes.create(assetType);\n                    }\n                }\n            })\n            .then((result) => {\n                this.alertService.create({\n                    label: assetType.id ? 'Asset type saved' : 'Asset type created',\n                    level: 'success',\n                });\n                if (finish) {\n                    return this.router.navigateToRoute('assets-list');\n                }\n                if (!assetType.id) {\n                    return this.router.navigateToRoute('assets-edit', { assetId: result.id });\n                }\n            })\n            .catch((e) => this.alertService.create({\n                label: e.message,\n                level: 'error',\n            }));\n    }\n\n    delete() {\n        return this.api.programAssetTypes.remove(this.assetType.id)\n            .then(() => {\n                this.alertService.create({\n                    label: 'Asset Removed',\n                    level: 'success',\n                });\n                this.router.navigateToRoute('assets-list');\n            });\n    }\n\n    cancel() {\n        this.router.navigateToRoute('assets-list');\n    }\n}\n","// Module\nvar code = \"<template> <require from=\\\"components/programs/field-edit-list/field-edit-list\\\"></require> <require from=\\\"components/mdc-json-field/mdc-json-field\\\"></require> <h3 class=\\\"align-header\\\">Edit Asset Type</h3> <mdc-text-field outlined class=\\\"mt-8\\\" value.bind=\\\"assetType.title & validate\\\" type=\\\"text\\\" label=\\\"Title\\\"> </mdc-text-field>  <mdc-text-field-helper-line> <mdc-text-field-helper-text validation>Required</mdc-text-field-helper-text> </mdc-text-field-helper-line> <mdc-text-field outlined class=\\\"mt-8\\\" value.bind=\\\"assetType.description & validate\\\" type=\\\"text\\\" label=\\\"Description\\\"> </mdc-text-field>  <mdc-text-field-helper-line> <mdc-text-field-helper-text validation>Required</mdc-text-field-helper-text> </mdc-text-field-helper-line> <h4>Geometry Type</h4> <mdc-form-field repeat.for=\\\"geom of geometryTypes\\\"> <label class=\\\"radio-label\\\"> <mdc-radio model.bind=\\\"geom\\\" checked.bind=\\\"assetType.type\\\"></mdc-radio> <span class=\\\"pr-4\\\">${geom}</span> </label> </mdc-form-field> <h4>Asset Schema Configuration</h4> <field-edit-list if.bind=\\\"!jsonEditor\\\" fields.two-way=\\\"assetType.assetSchema\\\"></field-edit-list> <label class=\\\"checkbox-label\\\"> <mdc-checkbox checked.bind=\\\"jsonEditor\\\"></mdc-checkbox> <span class=\\\"pr-4\\\">Show Advanced Editor</span> </label> <div if.bind=\\\"jsonEditor\\\"> <mdc-json-field value.two-way=\\\"assetType.assetSchema\\\"></mdc-json-field> </div> <div class=\\\"divider\\\"></div> <div class=\\\"my-8\\\"> <button if.bind=\\\"assetType.id\\\" class=\\\"button--color--danger float-left\\\" mdc-button raised mdc-icon=\\\"trash\\\" click.trigger=\\\"delete()\\\">Delete</button> <button click.trigger=\\\"submit(true)\\\" class=\\\"button--raised--secondary float-right\\\" mdc-button raised>Save and Finish</button> <button mdc-button class=\\\"float-right\\\" click.trigger=\\\"submit()\\\">Save</button> <button class=\\\"button--color--secondary float-right\\\" mdc-button click.trigger=\\\"cancel()\\\">Cancel</button> </div> </template> \";\n// Exports\nmodule.exports = code;","import { Paginated } from '@feathersjs/feathers';\nimport { ProgramAssetType, ProgramConfig } from '@wsb_dev/datafi-shared/lib/types';\nimport { autoinject } from 'aurelia-dependency-injection';\nimport { Redirect } from 'aurelia-router';\nimport { DatafiProAPI } from '../../../../services/api/DatafiProAPI';\nimport { AlertService } from '../../../../services/util/Alert';\nimport { ensureNumber } from '../../../../util/numbers/ensureNumber';\nimport { DialogService } from 'aurelia-dialog';\nimport { MDCDelete } from '../../../../components/mdc-delete-dialog/mdc-delete-dialog';\nimport { userHasPermission } from '@wsb_dev/datafi-shared/lib/util/users/userHasPermission';\n\n@autoinject\nexport class AssetsList {\n\n    programId: number;\n    assets: ProgramAssetType[];\n\n    constructor(\n        private api: DatafiProAPI,\n        private alerts: AlertService,\n        private dialogService: DialogService,\n    ) {\n    }\n\n    canActivate() {\n        if (userHasPermission(this.api.auth.me, '*', '*')) {\n            return true;\n        }\n        return new Redirect('/');\n    }\n\n    activate(params, config) {\n        this.programId = ensureNumber(config.settings.programId);\n        return this.updateConfigs();\n    }\n\n    updateConfigs() {\n        return this.api.programAssetTypes.find({ query: { program_id: this.programId, $sort: { title: 1 } } })\n            .then((result: Paginated<ProgramAssetType>) => this.assets = result.data);\n    }\n\n    delete(asset: ProgramAssetType) {\n\n        return this.dialogService.open({\n            viewModel: MDCDelete,\n            model: asset.id,\n        }).whenClosed((result) => {\n            if (result.wasCancelled) {\n                return;\n            }\n            this.api.programAssetTypes.remove(asset.id)\n                .then(() => {\n                    this.alerts.create({\n                        label: 'Asset type removed',\n                        dismissable: true,\n                    });\n                    return this.updateConfigs();\n                }).catch((e) => {\n                    this.alerts.create({\n                        label: `Error: ${e.message}`,\n                        level: 'error',\n                        dismissable: true,\n                    });\n                });\n        });\n\n    }\n}\n","// Module\nvar code = \"<template> <require from=\\\"components/admin/admin-table\\\"></require> <h1 class=\\\"text-center\\\">Assets</h1> <div> <mdc-data-table class=\\\"w-100\\\"> <table> <thead> <th>Title</th> <th>Description</th> <th>Type</th> <th>ID</th> <th></th> </thead> <tbody> <tr mdc-data-table-row repeat.for=\\\"asset of assets\\\"> <td>${asset.title}</td> <td>${asset.description}</td> <td>${asset.type}</td> <td>${asset.id}</td> <td> <a route-href=\\\"route: assets-edit; params.bind: {assetId: asset.id}\\\" mdc-button> <mdc-icon>edit</mdc-icon>Edit </a> <button class=\\\"button--color--danger\\\" mdc-button click.delegate=\\\"delete(asset)\\\"> <mdc-icon>delete</mdc-icon>Delete </button> </td> </tr> </tbody> </table> </mdc-data-table> </div> <br/> <div class=\\\"w-100 flex-1 justify-center py-4\\\"> <a route-href=\\\"route: assets-edit;  params.bind: {assetId: 0}\\\" raised mdc-button> <mdc-icon>add</mdc-icon>Create New </a> </div> </template> \";\n// Exports\nmodule.exports = code;","import { autoinject } from 'aurelia-framework';\nimport { DatafiProAPI } from '../../../services/api/DatafiProAPI';\nimport { ConfigType, ProgramConfig } from '@wsb_dev/datafi-shared/lib/types/ProgramConfig';\nimport { ValidationController, ValidationControllerFactory } from 'aurelia-validation';\nimport { AlertService } from '../../../services/util/Alert';\nimport { ValidatedProgramConfig } from '../../../types/ProgramConfig';\nimport { ensureNumber } from '../../../util/numbers/ensureNumber';\nimport { defaultLayerObjects, defaultMap } from '../../../components/projects/data/defaultMap';\nimport { Router } from 'aurelia-router';\nimport { DirtyChecker } from '../../../types/DirtyChecker';\nimport { Program } from '@wsb_dev/datafi-shared/lib/types';\nimport { ILayerConfigMeta } from '../../../components/ol-map-config/ol-map-config';\nimport { IUrlParams } from '../../../components/ol-map/sources/dfpSourceUrlGeojson';\nimport { AppConfig } from '../../../services/util/AppConfig';\nimport { flattenFields } from '@wsb_dev/datafi-shared/lib/util/surveys/flattenFields';\nimport { getFields } from '@wsb_dev/datafi-shared/lib/util/fields/getFields';\n\n@autoinject\nexport class ConfigsEdit extends DirtyChecker {\n    public dirtyProps: string[] = ['config'];\n    configId: number;\n    programId: number;\n    config: ProgramConfig;\n    program: Program;\n    validationController: ValidationController;\n    textField: HTMLElement;\n    selectedVariableText: string;\n    isModified = false;\n    showAdvancedEditor = false;\n\n    layerDefaults: Record<string, ILayerConfigMeta>;\n\n    constructor(\n        private api: DatafiProAPI,\n        private validationFactory: ValidationControllerFactory,\n        private alerts: AlertService,\n        private router: Router,\n        private appConfig: AppConfig,\n    ) {\n        super();\n    }\n\n    attached() {\n        this.validationController = this.validationFactory.createForCurrentScope();\n    }\n\n    async activate(params, config) {\n        this.programId = ensureNumber(config.settings.programId);\n        this.configId = ensureNumber(params.configId);\n\n        this.program = await this.api.programs.get(this.programId, { query: { $eager: '[surveys,assetTypes]' } });\n        this.config = await (this.configId ?\n            this.api.programConfigs.get(this.configId).then((result) => new ValidatedProgramConfig(result)) :\n            new ValidatedProgramConfig({\n                program_id: this.programId,\n                ...params.defaults,\n                data: this.getDefaultsForStoreType(params.defaults?.type),\n            })\n        );\n\n        if (!['ol-map', 'data-store'].includes(this.config.type)) {\n            this.showAdvancedEditor = true;\n        }\n\n        if (this.config.type === 'ol-map') {\n            this.populateMapLayers();\n        }\n\n        this.validationController = this.validationFactory.createForCurrentScope();\n        this.updateClones();\n    }\n\n    populateMapLayers() {\n        this.layerDefaults = {\n            ...defaultLayerObjects,\n            projectFeatures: {\n                config: {\n                    id: 'projectFeatures',\n                    label: 'Project Features',\n                    geometryType: 'polygon',\n                    visible: true,\n                    type: 'ol/layer/VectorImage',\n                    source: {\n                        type: 'dfp/source/VectorDFP',\n                        url: {\n                            type: 'url/dfp/GeoJSON',\n                            baseUrl: this.appConfig.API_HOST,\n                            typeId: 0,\n                            serviceType: 'projects',\n                            query: {},\n                            programId: this.programId,\n                        } as IUrlParams,\n                    },\n                },\n                fields: [\n                    ...flattenFields(getFields([\n                        {\n                            name: 'status',\n                            options: [{value: 'Open'}, {value: 'Closed'}],\n                        }],\n                    )),\n                    ...flattenFields(this.program.projectSchema)],\n            },\n        };\n        this.program.surveys.forEach((s) => {\n            this.layerDefaults[`surveys-${s.id}`] = {\n                fields: flattenFields(s.surveySchema),\n                config: {\n                    id: `surveys-${s.id}`,\n                    label: s.title,\n                    type: 'ol/layer/VectorImage',\n                    geometryType: 'point',\n                    visible: false,\n                    source: {\n                        type: 'dfp/source/VectorDFP',\n                        url: {\n                            type: 'url/dfp/GeoJSON',\n                            baseUrl: this.appConfig.API_HOST,\n                            typeId: s.id,\n                            serviceType: 'form-submissions',\n                            query: {},\n                            programId: this.programId,\n                        } as IUrlParams,\n                    },\n                },\n            } as ILayerConfigMeta;\n        });\n\n        this.program.assetTypes.forEach((a) => {\n            this.layerDefaults[`assets-${a.id}`] = {\n                fields: flattenFields(a.assetSchema),\n                config: {\n                    id: `assets-${a.id}`,\n                    label: a.title,\n                    geometryType: a.type,\n                    visible: false,\n                    source: {\n                        type: 'dfp/source/VectorDFP',\n                        url: {\n                            type: 'url/dfp/GeoJSON',\n                            baseUrl: this.appConfig.API_HOST,\n                            typeId: a.id,\n                            serviceType: 'programs-assets',\n                            query: {},\n                            programId: this.programId,\n                        } as IUrlParams,\n                    },\n                },\n            } as ILayerConfigMeta;\n        });\n    }\n\n    getDefaultsForStoreType(type?: ConfigType) {\n        if (!type) {\n            return {};\n        }\n\n        const defaults: Partial<Record<ConfigType, any>> = {\n            'data-store': {\n                query: {\n                    program_id: this.programId,\n                },\n                service: 'api/v1/form-submissions',\n            },\n            'ol-map': JSON.parse(JSON.stringify(defaultMap)),\n        };\n\n        return defaults[type] || {};\n    }\n\n    submit() {\n        return this.validationController.validate()\n            .then((result) => {\n                if (result.valid) {\n                    if (this.config.id) {\n                        this.updateMapQuery();\n                        return this.api.programConfigs.patch(this.config.id, this.config);\n                    }\n\n                    return this.api.programConfigs.create(this.config);\n                }\n            })\n            .then((result) => {\n                this.alerts.create({\n                    label: 'Config updated',\n                    level: 'success',\n                    dismissable: true,\n                });\n                Object.assign(this.config, result);\n                this.updateClones();\n                this.router.navigateBack();\n            })\n            .catch((e) => {\n                this.alerts.create({\n                    label: e.message,\n                    level: 'error',\n                    dismissable: true,\n                });\n            });\n\n    }\n\n    cancel() {\n        this.router.navigateBack();\n    }\n\n    async updateMapQuery() {\n        const result = await this.api.programConfigs.find({ query: { program_id: this.programId, type: 'dashboard' } }) as any;\n        const dashboardsToUpdate = result.data.filter((dashboard) => {\n            return (dashboard.data.items || [])\n                .flatMap((item) => item.config?.mapOptions?.layers || [])\n                .some((layer) => layer.id === `store-${this.config.id}`);\n        });\n\n        dashboardsToUpdate.forEach((dashboard) => {\n            (dashboard.data.items || [])\n                .flatMap((item) => item.config?.mapOptions?.layers || [])\n                .filter((layer) => layer.id === `store-${this.config.id}`)\n                .forEach((layer) => {\n                    layer.source.url.query = JSON.parse(JSON.stringify(this.config.data.query));\n                });\n        });\n\n        return await Promise.all(dashboardsToUpdate.map(async (dashboard) => {\n            await this.api.programConfigs.patch(dashboard.id, dashboard);\n        }));\n    }\n\n    populateConfigData(config: ProgramConfig): void {\n        if (config.type && (!config.data || JSON.stringify(config.data) === '{}')) {\n            config.data = this.getDefaultsForStoreType(config.type);\n            if (JSON.stringify(config.data) !== '{}') {\n                this.showAdvancedEditor = false;\n            }\n        }\n\n        if (config.type === 'ol-map') {\n            this.populateMapLayers();\n        }\n    }\n\n    populateVariable(variableName: string) {\n        if (!variableName) {\n            return;\n        }\n        const newText = `{{ ${variableName} }}`;\n        const el: HTMLTextAreaElement = this.textField.querySelector('textarea');\n        const [start, end] = [el.selectionStart, el.selectionEnd];\n        el.setRangeText(newText, start, end, 'select');\n        this.selectedVariableText = '';\n    }\n\n}\n","// Module\nvar code = \"<template> <require from=\\\"components/mdc-json-field/mdc-json-field\\\"></require> <require from=\\\"components/ol-map-config/ol-map-config\\\"></require>  <require from=\\\"components/dashboard-store-config/dashboard-store-config\\\"></require> <require from=\\\"components/ol-map/ol-map\\\"></require> <require from=\\\"components/ol-map-config/ol-map-config\\\"></require> <div class=\\\"p-centered p-2 mw-700\\\"> <mdc-select if.bind=\\\"config.type !== 'dashboard'\\\" outlined class=\\\"my-4 w-100\\\" value.bind=\\\"config.type\\\" label=\\\"Config Type\\\" mdcselect:change.delegate=\\\"populateConfigData(config)\\\" disabled.bind=\\\"config.type\\\"> <mdc-list> <mdc-list-item value=\\\"ol-map\\\">Openlayers Map</mdc-list-item> <mdc-list-item value=\\\"data-store\\\">Data Store</mdc-list-item> </mdc-list> </mdc-select> <mdc-select-helper-text validation></mdc-select-helper-text> <mdc-text-field outlined class=\\\"my-4 w-100\\\" value.bind=\\\"config.label\\\" type=\\\"text\\\" label=\\\"Label\\\" placeholder=\\\"A short and unique label for this item\\\"> </mdc-text-field> <mdc-text-field-helper-line> <mdc-text-field-helper-text validation>Required</mdc-text-field-helper-text> </mdc-text-field-helper-line> <mdc-text-field outlined class=\\\"my-4 w-100\\\" value.bind=\\\"config.description\\\" type=\\\"text\\\" label=\\\"Description\\\" placeholder=\\\"A helpful statement to explain the purpose of this item\\\"> </mdc-text-field> <mdc-text-field-helper-line> <mdc-text-field-helper-text validation>Required</mdc-text-field-helper-text> </mdc-text-field-helper-line> <mdc-form-field> <button mdc-switch selected.bind=\\\"showAdvancedEditor\\\"></button> <label>Advanced Editor </label></mdc-form-field> <div class=\\\"my-4\\\" if.bind=\\\"showAdvancedEditor\\\"> <mdc-json-field value.two-way=\\\"config.data\\\" ref=\\\"textField\\\"></mdc-json-field> <mdc-select if.bind=\\\"program.templateScope.length\\\" outlined class=\\\"mt-8 w-100\\\" value.bind=\\\"selectedVariableText\\\" label=\\\"Insert variable at cursor location\\\" mdcselect:change.delegate=\\\"populateVariable(selectedVariableText)\\\"> <mdc-list> <mdc-list-item>Select a value to insert</mdc-list-item> <mdc-list-item repeat.for=\\\"val of program.templateScope\\\" value.bind=\\\"val\\\">${val}</mdc-list-item> </mdc-list> </mdc-select> </div> <div else class=\\\"my-8\\\"> <div if.bind=\\\"config.type === 'ol-map'\\\"> <ol-map-config map-config.two-way=\\\"config.data\\\" layer-defaults.bind=\\\"layerDefaults\\\"></ol-map-config> </div> <div else> <dashboard-store-config if.bind=\\\"config.type === 'data-store'\\\" value.bind=\\\"config.data\\\" program-id.bind=\\\"config.program_id\\\"></dashboard-store-config> </div> </div> <div class=\\\"text-center mb-4\\\"> <button class=\\\"button--color--secondary mt-3\\\" mdc-button click.trigger=\\\"cancel()\\\">Cancel</button> <button class=\\\"button--raised--secondary mt-3\\\" mdc-button raised click.trigger=\\\"submit()\\\">Save</button> </div> </div> </template>\";\n// Exports\nmodule.exports = code;","import { autoinject } from 'aurelia-dependency-injection';\nimport { DirtyChecker } from 'types/DirtyChecker';\nimport { Program } from 'types/Program';\nimport { bindable } from 'aurelia-framework';\nimport { DatafiProAPI } from 'services/api/DatafiProAPI';\nimport { AlertService } from 'services/util/Alert';\n\n@autoinject\nexport class FileFoldersEdit extends DirtyChecker {\n    public dirtyProps: string[] = ['program'];\n    @bindable program: Program;\n\n    constructor(\n        private api: DatafiProAPI,\n        private alerts: AlertService,\n    ) { super(); }\n\n    activate(params: any, config) {\n        this.program = new Program(config.settings.program, this.api.files);\n\n        if (!this.program.fileFolders) {\n            this.program.fileFolders = [];\n        }\n\n        this.updateClones();\n    }\n\n    save() {\n        this.api.programs.patch(this.program.id, this.program)\n            .then((result) => {\n                this.program = Object.assign(this.program, result);\n                this.updateClones();\n\n                this.alerts.create({\n                    label: 'File folder settings saved',\n                    level: 'success',\n                    dismissable: true,\n                });\n\n            }).catch((e) => {\n                this.alerts.create({\n                    label: e.message,\n                    level: 'error',\n                    dismissable: true,\n                });\n            });\n    }\n}\n","// Module\nvar code = \"<template> <require from=\\\"../../../components/mdc-json-field/mdc-json-field\\\"></require> <require from=\\\"../../../components/programs/folder-edit-list/folder-edit-list\\\"></require> <div class=\\\"mw-800 p-centered w-100\\\"> <h1 class=\\\"text-center\\\">File Folders</h1> <div class=\\\"divider text-center\\\" data-content=\\\"File Folders Configuration\\\"></div> <p>Define program folders for images and files </p> <folder-edit-list if.bind=\\\"!jsonEditorFileFolder\\\" folders.two-way=\\\"program.fileFolders\\\"></folder-edit-list> <div if.bind=\\\"jsonEditorFileFolder\\\"> <mdc-json-field value.two-way=\\\"program.fileFolders\\\"></mdc-json-field> </div> <label class=\\\"checkbox-label\\\"> <mdc-checkbox checked.bind=\\\"jsonEditorFileFolder\\\"></mdc-checkbox> <span class=\\\"pr-4\\\">Show Advanced Editor</span> </label> <div class=\\\"text-center mb-4\\\"> <button class=\\\"button--raised--secondary mt-3\\\" mdc-button raised click.trigger=\\\"save()\\\">Save</button> </div> </div> </template> \";\n// Exports\nmodule.exports = code;","import { Job } from '@wsb_dev/datafi-shared/lib/types';\nimport { autoinject } from 'aurelia-dependency-injection';\nimport { Router, Redirect } from 'aurelia-router';\nimport { DatafiProAPI } from '../../../services/api/DatafiProAPI';\nimport { userHasPermission } from '@wsb_dev/datafi-shared/lib/util/users/userHasPermission';\n\n@autoinject\nexport class JobDetail {\n    jobId: number;\n    webhookId: number;\n    programId: number;\n    job: Job<any>;\n    loading: boolean;\n    timer: ReturnType<typeof setInterval>;\n\n    constructor(private api: DatafiProAPI, private router: Router) { }\n\n    canActivate() {\n        if (userHasPermission(this.api.auth.me, '*', '*')) {\n            return true;\n        }\n        return new Redirect('/');\n    }\n\n    activate(params, config) {\n        this.webhookId = params.id;\n        this.jobId = params.jobId;\n        this.programId = config.settings.programId;\n\n        this.updateJob();\n    }\n\n    detached() {\n        this.clearTimer();\n    }\n\n    async updateJob(retryTimeout = 4000) {\n        this.loading = true;\n        return this.api.jobs.get(this.jobId, { query: { program_id: this.programId, $select: ['id', 'status', 'error', 'result', 'data'] } }).then((result) => {\n            this.job = result;\n\n            // if job is still pending, re-fetch the job data\n            if (!['completed', 'failed'].includes(result.status)) {\n                this.scheduleTimer(retryTimeout);\n            } else {\n                this.clearTimer();\n            }\n\n        })\n            .finally(() => this.loading = false);\n    }\n\n    scheduleTimer(retryTimeout) {\n        if (this.timer) {\n            return;\n        }\n        this.timer = setInterval(() => this.updateJob(), retryTimeout);\n    }\n\n    clearTimer() {\n        if (this.timer) {\n            clearInterval(this.timer);\n            this.timer = undefined;\n        }\n    }\n}\n","// Module\nvar code = \"<template> <require from=\\\"components/mdc-json-field/mdc-json-field\\\"></require> <h2>Job #${jobId} <span if.bind=\\\"job.data.retryId\\\"> <a route-href=\\\"route: webhook-job-detail; params.bind: {webhookId: job.data.webhook_id, jobId: job.data.retryId};\\\">(Retry of Job ID #${job.data.retryId})</a> </span>: <span class=\\\"${job.status === 'failed' ? 'text-error' : ''} ${job.status === 'completed' ? 'text-success': ''}\\\">${job.status | jobStatus} </span> </h2> <mdc-circular-progress size=\\\"100\\\" stroke-width=\\\"2\\\" if.bind=\\\"!job && loading\\\"></mdc-circular-progress> <div else> <h3 if.bind=\\\"job.status  === 'failed'\\\" class=\\\"text-error\\\">${job.error}</h3> <h3>Data:</h3> <mdc-json-field value.bind=\\\"job.data\\\"></mdc-json-field> <h3>Result:</h3> <mdc-json-field value.bind=\\\"job.result\\\"></mdc-json-field> </div> </template>\";\n// Exports\nmodule.exports = code;","import { autoinject } from 'aurelia-framework';\nimport { DatafiProAPI } from 'services/api/DatafiProAPI';\nimport { AlertService } from '../../../../services/util/Alert';\nimport { AppConfig } from '../../../../services/util/AppConfig';\nimport { ProgramConfig } from '@wsb_dev/datafi-shared/lib/types/ProgramConfig';\nimport { Program } from '@wsb_dev/datafi-shared/lib/types';\nimport { DirtyChecker } from '../../../../types/DirtyChecker';\nimport { ILayerConfigMeta } from '../../../../components/ol-map-config/ol-map-config';\nimport { IUrlParams } from '../../../../components/ol-map/sources/dfpSourceUrlGeojson';\nimport { defaultLayerObjects, defaultMap } from '../../../../components/projects/data/defaultMap';\nimport { ensureNumber } from '../../../../util/numbers/ensureNumber';\nimport { flattenFields } from '@wsb_dev/datafi-shared/lib/util/surveys/flattenFields';\nimport { getFields } from '@wsb_dev/datafi-shared/lib/util/fields/getFields';\n\n@autoinject\nexport class MapEdit extends DirtyChecker {\n    public dirtyProps: string[] = ['config'];\n    programId: number;\n    config: ProgramConfig;\n    program: Program;\n    textField: HTMLElement;\n    selectedVariableText: string;\n    isModified = false;\n    showAdvancedEditor = false;\n\n    layerDefaults: Record<string, ILayerConfigMeta>;\n\n    constructor(\n        private api: DatafiProAPI,\n        private alerts: AlertService,\n        private appConfig: AppConfig,\n    ) { super(); }\n\n    async activate(params, config) {\n        this.programId = ensureNumber(config.settings.programId);\n        this.program = config.settings.program;\n\n        const mapConfig = this.program.configs?.find((config) => config.type === 'ol-map');\n        this.config = await (mapConfig ?\n            this.api.programConfigs.get(mapConfig.id) :\n            {\n                program_id: this.programId,\n                type: 'ol-map',\n                label: 'Program Map',\n                description: 'The map configuration for the program.',\n                scopes: 'program',\n                data: defaultMap,\n            }\n        );\n\n        this.populateMapLayers();\n        this.updateClones();\n    }\n\n    populateMapLayers() {\n        this.layerDefaults = {\n            ...defaultLayerObjects,\n            projectFeatures: {\n                config: {\n                    id: 'projectFeatures',\n                    label: 'Project Features',\n                    geometryType: 'polygon',\n                    visible: true,\n                    type: 'ol/layer/VectorImage',\n                    source: {\n                        type: 'dfp/source/VectorDFP',\n                        url: {\n                            type: 'url/dfp/GeoJSON',\n                            baseUrl: this.appConfig.API_HOST,\n                            typeId: 0,\n                            serviceType: 'projects',\n                            query: {},\n                            programId: this.programId,\n                        } as IUrlParams,\n                    },\n                },\n                fields: [\n                    ...flattenFields(getFields([\n                        {\n                            name: 'status',\n                            options: [{ value: 'Open' }, { value: 'Closed' }],\n                        }],\n                    )),\n                    ...flattenFields(this.program.projectSchema)],\n            },\n        };\n        this.program.surveys.forEach((s) => {\n            this.layerDefaults[`surveys-${s.id}`] = {\n                fields: flattenFields(s.surveySchema),\n                config: {\n                    id: `surveys-${s.id}`,\n                    label: s.title,\n                    type: 'ol/layer/VectorImage',\n                    geometryType: 'point',\n                    visible: false,\n                    source: {\n                        type: 'dfp/source/VectorDFP',\n                        url: {\n                            type: 'url/dfp/GeoJSON',\n                            baseUrl: this.appConfig.API_HOST,\n                            typeId: s.id,\n                            serviceType: 'form-submissions',\n                            query: {},\n                            programId: this.programId,\n                        } as IUrlParams,\n                    },\n                },\n            } as ILayerConfigMeta;\n        });\n\n        this.program.assetTypes.forEach((a) => {\n            this.layerDefaults[`assets-${a.id}`] = {\n                fields: flattenFields(a.assetSchema),\n                config: {\n                    id: `assets-${a.id}`,\n                    label: a.title,\n                    geometryType: a.type,\n                    visible: false,\n                    source: {\n                        type: 'dfp/source/VectorDFP',\n                        url: {\n                            type: 'url/dfp/GeoJSON',\n                            baseUrl: this.appConfig.API_HOST,\n                            typeId: a.id,\n                            serviceType: 'programs-assets',\n                            query: {},\n                            programId: this.programId,\n                        } as IUrlParams,\n                    },\n                },\n            } as ILayerConfigMeta;\n        });\n    }\n\n    save() {\n        if (this.config.id) this.updateMapQuery();\n        const promise = this.config.id ?\n            this.api.programConfigs.patch(this.config.id, this.config) :\n            this.api.programConfigs.create(this.config);\n\n        return promise\n            .then(async (result) => {\n                await this.api.programs.patch(this.program.id, this.program);\n                this.alerts.create({\n                    label: 'Map updated',\n                    level: 'success',\n                    dismissable: true,\n                });\n                Object.assign(this.config, result);\n                this.updateClones();\n            })\n            .catch((e) => {\n                this.alerts.create({\n                    label: e.message,\n                    level: 'error',\n                    dismissable: true,\n                });\n            });\n\n    }\n\n    async updateMapQuery() {\n        const result = await this.api.programConfigs.find({ query: { program_id: this.programId, type: 'dashboard' } }) as any;\n        const dashboardsToUpdate = result.data.filter((dashboard) => {\n            return (dashboard.data.items || [])\n                .flatMap((item) => item.config?.mapOptions?.layers || [])\n                .some((layer) => layer.id === `store-${this.config.id}`);\n        });\n\n        dashboardsToUpdate.forEach((dashboard) => {\n            (dashboard.data.items || [])\n                .flatMap((item) => item.config?.mapOptions?.layers || [])\n                .filter((layer) => layer.id === `store-${this.config.id}`)\n                .forEach((layer) => {\n                    layer.source.url.query = JSON.parse(JSON.stringify(this.config.data.query));\n                });\n        });\n\n        return await Promise.all(dashboardsToUpdate.map(async (dashboard) => {\n            await this.api.programConfigs.patch(dashboard.id, dashboard);\n        }));\n    }\n\n    populateVariable(variableName: string) {\n        if (!variableName) {\n            return;\n        }\n        const newText = `{{ ${variableName} }}`;\n        const el: HTMLTextAreaElement = this.textField.querySelector('textarea');\n        const [start, end] = [el.selectionStart, el.selectionEnd];\n        el.setRangeText(newText, start, end, 'select');\n        this.selectedVariableText = '';\n    }\n\n}\n","// Module\nvar code = \"<template> <require from=\\\"components/mdc-json-field/mdc-json-field\\\"></require> <require from=\\\"components/ol-map/ol-map\\\"></require> <require from=\\\"components/ol-map-config/ol-map-config\\\"></require> <h1 class=\\\"text-center\\\">Map</h1> <div class=\\\"mw-800 p-centered w-100\\\"> <mdc-form-field> <button mdc-switch selected.bind=\\\"showAdvancedEditor\\\"></button> <label>Advanced Editor </label></mdc-form-field> <div class=\\\"my-4\\\" if.bind=\\\"showAdvancedEditor\\\"> <mdc-json-field value.two-way=\\\"config.data\\\" ref=\\\"textField\\\"></mdc-json-field> <mdc-select if.bind=\\\"program.templateScope.length\\\" outlined class=\\\"mt-8 w-100\\\" value.bind=\\\"selectedVariableText\\\" label=\\\"Insert variable at cursor location\\\" mdcselect:change.delegate=\\\"populateVariable(selectedVariableText)\\\"> <mdc-list> <mdc-list-item>Select a value to insert</mdc-list-item> <mdc-list-item repeat.for=\\\"val of program.templateScope\\\" value.bind=\\\"val\\\">${val}</mdc-list-item> </mdc-list> </mdc-select> </div> <ol-map-config else map-config.two-way=\\\"config.data\\\" layer-defaults.bind=\\\"layerDefaults\\\"></ol-map-config> </div> <div class=\\\"text-center mb-4\\\"> <button class=\\\"button--raised--secondary mt-3\\\" mdc-button raised click.trigger=\\\"save()\\\">Save</button> </div> </template> \";\n// Exports\nmodule.exports = code;","import { Field } from '@wsb_dev/datafi-shared/lib/types/Field';\nimport { getFields } from '@wsb_dev/datafi-shared/lib/util/fields/getFields';\nimport { PLATFORM, autoinject } from 'aurelia-framework';\nimport { ValidationController, ValidationControllerFactory } from 'aurelia-validation';\nimport { DatafiProAPI } from '../../../services/api/DatafiProAPI';\nimport { Program } from '../../../types/Program';\nimport { ThumbnailJobData } from '@wsb_dev/datafi-shared/lib/types/jobs/ImageJob';\nimport { AlertService } from '../../../services/util/Alert';\nimport { ProgramEditOrganizations } from './program-edit-organizations/program-edit-organizations';\nimport { DialogService } from 'aurelia-dialog';\nimport { ValidatedOrganization } from '../../../types/Organizations';\nimport { generatePath } from '@wsb_dev/datafi-shared/lib/util/files/generatePath';\nimport { TourService } from '../../../services/tour/TourService';\nimport { DirtyChecker } from 'types/DirtyChecker';\nimport { Router } from 'aurelia-router';\nimport { Paginated } from '@feathersjs/feathers';\nimport { ProgramUserRole } from '@wsb_dev/datafi-shared/lib/types';\n\nPLATFORM.moduleName('./program-edit-organizations/program-edit-organizations');\n\n@autoinject\nexport class ProgramEdit extends DirtyChecker {\n    public dirtyProps: string[] = ['program'];\n    validationController: ValidationController;\n    program: Program;\n    sort: number;\n    programId: number;\n    isProcessing: boolean;\n    orgName: ValidatedOrganization;\n\n    basicFields: Field[] = getFields([\n        { name: 'title' },\n        { name: 'description' },\n        {\n            name: 'settings', type: 'object', fields: [\n                {\n                    name: 'tabs', type: 'object', fields: [\n                        { name: 'projects', type: 'select', options: [{ value: true, label: 'Active' }, { value: false, label: 'Hidden' }] },\n                        { name: 'collect', type: 'select', options: [{ value: true, label: 'Active' }, { value: false, label: 'Hidden' }] },\n                        { name: 'files', type: 'select', options: [{ value: true, label: 'Active' }, { value: false, label: 'Hidden' }] },\n                    ],\n                },\n                {\n                    type: 'object',\n                    name: 'userLocation',\n                    label: 'User Location',\n                    fields: [\n                        { name: 'autoEnabled', label: 'Auto track users location', type: 'select', options: [{ value: true, label: 'Yes' }, { value: false, label: 'No' }] },\n                        { name: 'source', label: 'User location source', type: 'select', options: [{ value: 'gps' }, { value: 'profile' }] },\n                    ],\n                },\n            ],\n        },\n    ])\n\n    constructor(\n        private validationFactory: ValidationControllerFactory,\n        private api: DatafiProAPI,\n        private alerts: AlertService,\n        private dialogs: DialogService,\n        private tourDriver: TourService,\n        private router: Router,\n    ) { super(); }\n\n    async activate(params: any, config) {\n        this.program = new Program(config.settings.program, this.api.files);\n        this.program.getThumbnail();\n        this.sort = -1;\n        this.programId = parseInt(params.id, 10);\n\n        if (!this.program.settings) {\n            this.program.settings = {};\n        }\n\n        if (!this.program.settings?.tabs) {\n            this.program.settings.tabs = {\n                files: true,\n                collect: true,\n                projects: true,\n            };\n        }\n\n        if (!this.program.fileFolders) {\n            this.program.fileFolders = [\n                { label: 'Documentation', value: 'docs' },\n                { label: 'Images', value: 'images' },\n            ];\n        }\n\n        if (!this.program.thumbnailUrl) {\n            this.program.thumbnailUrl = '';\n        }\n\n        if (!this.program.settings.userLocation) {\n            this.program.settings.userLocation = {\n                autoEnabled: false,\n                source: 'gps',\n            };\n        }\n        if (this.program.managementOrganizationId) {\n            this.api.organizations.find({ query: { $limit: 50 } }).then((orgs: ValidatedOrganization) => {\n                this.orgName = orgs.data.find((org) => org.id === this.program.managementOrganizationId);\n            });\n        }\n\n        this.validationController = this.validationFactory.createForCurrentScope();\n\n        this.updateClones();\n    }\n\n    attached() {\n        this.tourDriver.setTour('programSettingsTour');\n    }\n\n    detached() {\n        this.tourDriver.setTour();\n    }\n\n    async updateProgramThumbnail($event) {\n        this.isProcessing = true;\n        const fileId = $event.detail.created[0].id;\n        const job = await this.api.jobs.create({\n            name: 'thumbnail',\n            data: {\n                id: fileId,\n                width: 720,\n            } as ThumbnailJobData,\n        }, {\n            query: { $sync: true },\n        });\n        this.program.thumbnailUrl = job.result.id;\n        this.program.replaceThumbnail();\n        this.alerts.create({\n            level: 'success',\n            label: 'Program thumbnail updated, please save to see the changes',\n            dismissable: true,\n        });\n        this.isProcessing = false;\n    }\n\n    getProgramImageName = (f: File): string => {\n        return generatePath({\n            name: 'thumbnail',\n            programId: this.programId,\n            fileName: f.name,\n        });\n    }\n\n    manageOrg() {\n        return this.dialogs.open({\n            viewModel: ProgramEditOrganizations,\n            model: this.programId,\n        }).whenClosed((result) => {\n            if (result.wasCancelled) {\n                return;\n            }\n            this.program.managementOrganizationId = result.output.id;\n            this.orgName = result.output;\n            this.program.orgUpdated = true;\n        });\n    }\n\n    async updateProgramUserRoles() {\n        await this.api.programUsersRoles.find({\n            query: {\n                program_id: this.program.id,\n            },\n        }).then((result: Paginated<ProgramUserRole>) => {\n            if (result.data.length) {\n                return Promise.all(result.data.map(async(role) => {\n                    return this.api.programUsersRoles.patch(role.id, {\n                        program_org_id: this.program.managementOrganizationId,\n                    });\n                }));\n            }\n        }).catch((e) => {\n            this.alerts.create({\n                label: e.message,\n                level: 'error',\n                dismissable: true,\n            });\n        });\n    }\n\n    save() {\n        return this.validationController.validate().then((result) => {\n            if (!result.valid) {\n                throw new Error('Form is not valid');\n            }\n            if (this.program.orgUpdated) {\n                this.updateProgramUserRoles();\n                delete this.program.orgUpdated;\n            }\n\n            return (this.program.id ?\n                this.api.programs.patch(this.program.id, this.program) :\n                this.api.programs.create(this.program)\n            );\n        }).then((result) => {\n            if (!this.program.id) {\n                this.updateClones();\n                return this.router.navigateToRoute('program/settings', { id: result.id });\n            }\n            this.program = new Program (result, this.api.files);\n            this.updateClones();\n            this.program.getThumbnail();\n\n            this.alerts.create({\n                label: 'Settings saved',\n                level: 'success',\n                dismissable: true,\n            });\n\n        }).catch((e) => {\n            this.alerts.create({\n                label: e.message,\n                level: 'error',\n                dismissable: true,\n            });\n        });\n    }\n}\n","import { Paginated } from '@feathersjs/feathers';\nimport { autoinject } from 'aurelia-dependency-injection';\nimport { DialogController } from 'aurelia-dialog';\nimport { DatafiProAPI } from '../../../../services/api/DatafiProAPI';\nimport { AlertService } from '../../../../services/util/Alert';\nimport { ValidatedOrganization } from '../../../../types/Organizations';\n\n@autoinject\nexport class ProgramEditOrganizations {\n    orgs: ValidatedOrganization[];\n    selection: ValidatedOrganization;\n    confirmation: boolean;\n\n    constructor(\n        private dialogController: DialogController,\n        private api: DatafiProAPI,\n        private alerts: AlertService,\n    ) { }\n\n    async activate() {\n        await this.api.organizations.find({query: {$limit: 50}}).then((orgs: Paginated<ValidatedOrganization>) => this.orgs = orgs.data.filter((org) => org.id !== 0));\n    }\n\n    submit() {\n        if (this.selection && this.confirmation) {\n            this.alerts.create({\n                label: 'Organization has been activated. Save the program to persist changes',\n                level: 'success',\n                dismissable: true,\n            });\n            return this.dialogController.ok(this.selection);\n        }\n    }\n}\n","// Module\nvar code = \"<template> <ux-dialog class=\\\"mw-400\\\"> <ux-dialog-header> <h3 class=\\\"align-header\\\">Set Organization</h3> <button class=\\\"button--color--secondary float-right\\\" icon=\\\"close\\\" mdc-icon-button click.trigger=\\\"dialogController.cancel()\\\"></button> </ux-dialog-header> <ux-dialog-body> <p class=\\\"mb-2\\\"> Users associated with the assigned organization have access to all submitted data. Other users will only see submitted data from their organization. </p> <p> <strong>Warning:</strong> Setting an organization for this program is an irreversible action. Please ensure you have selected the correct organization before proceeding. </p> <mdc-select fixed class=\\\"my-8 w-100\\\" value.bind=\\\"selection\\\" label=\\\"Select an Organization\\\"> <mdc-list> <mdc-list-item repeat.for=\\\"o of orgs\\\" value.bind=\\\"o\\\"> ${o.name}</mdc-list-item> </mdc-list> </mdc-select> <div class=\\\"mt-8\\\" if.bind=\\\"selection\\\"> <mdc-form-field> <mdc-checkbox checked.bind=\\\"confirmation\\\"></mdc-checkbox> <label>I understand that setting an Organization on this program CANNOT be edited.</label> </mdc-form-field> </div> </ux-dialog-body> <ux-dialog-footer> <button class=\\\"float-left button--color--secondary\\\" mdc-button click.trigger=\\\"dialogController.cancel()\\\">Cancel</button> <button attach-focus disabled.bind=\\\"!confirmation\\\" class=\\\"button--raised--secondary\\\" mdc-button raised click.trigger=\\\"submit()\\\">Accept</button> </ux-dialog-footer> <div class=\\\"mdc-dialog__scrim\\\"></div> </ux-dialog> </template>\";\n// Exports\nmodule.exports = code;","// Module\nvar code = \"<template> <require from=\\\"../../../components/mdc-dynamic-form/mdc-dynamic-form\\\"></require> <require from=\\\"../../../components/mdc-upload-field/mdc-upload-field\\\"></require> <div class=\\\"p-centered mw-840 w-100\\\"> <h1 class=\\\"text-center\\\">Program</h1> <div class=\\\"columns\\\"> <div class=\\\"column col-6 col-md-12 pr-4\\\"> <div data-tour-id=\\\"basic-settings\\\"> <div class=\\\"divider text-center\\\" data-content=\\\"Basic Information\\\"></div> <mdc-dynamic-form object.bind=\\\"program\\\" schema.bind=\\\"basicFields\\\"></mdc-dynamic-form> </div> </div> <div class=\\\"column col-6 col-md-12 pl-3\\\"> <div class=\\\"divider text-center\\\" data-content=\\\"Cover Photo\\\"></div> <p if.bind=\\\"!program.id\\\" class=\\\"text-center\\\" data-tour-id=\\\"program-photo\\\">Please save the program before uploading a photo</p> <div if.bind=\\\"program.id\\\" class=\\\"text-center\\\" data-tour-id=\\\"program-photo\\\"> <div if.bind=\\\"isProcessing\\\" class=\\\"d-block w-100\\\"> <p>Processing, please wait...</p> <mdc-circular-progress size=\\\"100\\\" stroke-width=\\\"2\\\"></mdc-circular-progress> </div> <div else class=\\\"overflow-hidden mh-100\\\"> <img if.bind=\\\"program._blobs.thumbnail.url\\\" src=\\\"${program._blobs.thumbnail.url}\\\" alt=\\\"Program thumbnail preview\\\" class=\\\"card__image w-auto\\\"/> <mdc-icon else class=\\\"card__image icon-xlg\\\">image</mdc-icon> </div> <div class=\\\"divider\\\"></div> <p>Upload a new Cover Photo:</p> <mdc-upload-field get-file-name.bind=\\\"getProgramImageName\\\" single.bind=\\\"true\\\" created.trigger=\\\"updateProgramThumbnail($event)\\\"> </mdc-upload-field> <mdc-text-field class=\\\"mt-3\\\" value.bind=\\\"program.thumbnailUrl & validate\\\" type=\\\"text\\\" label=\\\"URL or Thumbnail path\\\"> </mdc-text-field> <mdc-text-field-helper-line class=\\\"mb-7\\\"> <mdc-text-field-helper-text validation>Required</mdc-text-field-helper-text> </mdc-text-field-helper-line> </div> <div class=\\\"divider dash-editor text-center\\\" data-content=\\\"Organization Management\\\"></div> <div class=\\\"text-center\\\" data-tour-id=\\\"set-organization\\\"> <button mdc-button raised class=\\\"button--color--wsb-yellow\\\" click.delegate=\\\"manageOrg()\\\" disabled.bind=\\\"program.managementOrganizationId\\\">Set Organization</button> <div if.bind=\\\"program.managementOrganizationId\\\" class=\\\"mt-2\\\"> <p>Organization <strong>${orgName.name}</strong> has been set for this program</p> </div> </div> </div> </div> <div class=\\\"text-center my-4\\\"> <button class=\\\"button--raised--secondary mt-3\\\" mdc-button raised click.trigger=\\\"save()\\\">Save</button> </div> </div> </template> \";\n// Exports\nmodule.exports = code;","import { bindable, autoinject, LogManager, PLATFORM } from 'aurelia-framework';\nimport { ValidationController, ValidationControllerFactory } from 'aurelia-validation';\nimport { Program } from '../../../types/Program';\nimport { DialogService } from 'aurelia-dialog';\nimport { FilterDialog } from '../../../components/filter-dialog/filter-dialog';\nimport { Filter } from '@wsb_dev/datafi-shared/lib/types';\nimport { FilterActivateParams } from '@wsb_dev/datafi-shared/lib/types/Filter';\nimport { filtersToQuery } from '@wsb_dev/datafi-shared/lib/util/fields/filtersToQuery';\nimport { queryToFilter } from '@wsb_dev/datafi-shared/lib/util/fields/queryToFilter';\nimport { projectFilters } from '../../../types/Project';\nimport { FileFolder } from '@wsb_dev/datafi-shared/lib/types/FileFolder';\nimport { BatchFieldEdit } from '../batch-field-edit/batch-field-edit';\nimport { DirtyChecker } from '../../../types/DirtyChecker';\nimport { Redirect } from 'aurelia-router';\nimport { DatafiProAPI } from 'services/api/DatafiProAPI';\nimport { AlertService } from 'services/util/Alert';\n\nPLATFORM.moduleName('./../batch-field-edit/batch-field-edit');\nconst logger = LogManager.getLogger('dfp:project-editor');\n\n@autoinject\nexport class ProjectEdit extends DirtyChecker {\n    public dirtyProps: string[] = ['program'];\n    validationController: ValidationController;\n    @bindable program: Program;\n    @bindable sort: number;\n    @bindable programId: number;\n    @bindable currentProjectFilters: Filter[];\n    @bindable fileFolders: FileFolder[];\n\n    constructor(\n        private validationFactory: ValidationControllerFactory,\n        private dialogService: DialogService,\n        private api: DatafiProAPI,\n        private alerts: AlertService,\n    ) {\n        super();\n        this.validationController = this.validationFactory.createForCurrentScope();\n    }\n\n    canActivate(params: any, config) {\n        if (!parseInt(params.id, 10)) return new Redirect('/program-edit');\n    }\n\n    async activate(params: any, config) {\n        this.sort = -1;\n        this.programId = parseInt(params.id, 10);\n        this.program = new Program(config.settings.program, this.api.files);\n\n        if (!this.program.projectQuery) {\n            this.program.projectQuery = {};\n        }\n\n        if (!this.program.projectSchema) {\n            this.program.projectSchema = [];\n        }\n\n        if (!this.currentProjectFilters) {\n            this.currentProjectFilters = [\n                ...projectFilters as Filter[],\n                ...this.program.projectSchema,\n            ];\n        }\n\n        // ensure 'metadata' is included in path.\n        this.program.projectSchema.forEach((field) => {\n            if (!field.path || !field.path.startsWith('metadata.')) {\n                field.path = `metadata.${field.name}`;\n            }\n        });\n\n        this.currentProjectFilters = queryToFilter(this.currentProjectFilters, [], this.program.projectQuery);\n        this.updateClones();\n    }\n\n    buildQuery(): void {\n        this.dialogService.open({\n            viewModel: FilterDialog,\n            model: {\n                filterProperties: this.currentProjectFilters,\n            } as FilterActivateParams,\n        }).whenClosed((result) => {\n            if (result.wasCancelled) {\n                return;\n            } else {\n                this.program.projectQuery = filtersToQuery(result.output);\n                this.currentProjectFilters = result.output;\n            }\n        });\n    }\n\n    batchEditFields() {\n        return this.dialogService.open({\n            viewModel: BatchFieldEdit,\n            model: {model: this.program.projectSchema },\n        }).whenClosed((result) => {\n            if (result.wasCancelled) {\n                return;\n            }\n            this.program.projectSchema = result.output;\n            logger.debug('batch updated fields', this.program);\n        });\n    }\n\n    save() {\n        return this.validationController.validate().then((result) => {\n            if (!result.valid) {\n                throw new Error('Form is not valid');\n            }\n\n            return this.api.programs.patch(this.program.id, this.program);\n        }).then((result) => {\n            this.program = Object.assign(this.program, result);\n            this.updateClones();\n\n            this.alerts.create({\n                label: 'Project settings saved',\n                level: 'success',\n                dismissable: true,\n            });\n\n        }).catch((e) => {\n            this.alerts.create({\n                label: e.message,\n                level: 'error',\n                dismissable: true,\n            });\n        });\n    }\n}\n","// Module\nvar code = \"<template> <require from=\\\"../../../components/mdc-dynamic-form/mdc-dynamic-form\\\"></require> <require from=\\\"../../../components/programs/field-edit-list/field-edit-list\\\"></require> <require from=\\\"../../../components/mdc-json-field/mdc-json-field\\\"></require> <require from=\\\"../../../components/programs/folder-edit-list/folder-edit-list\\\"></require> <div class=\\\"mw-800 p-centered w-100\\\"> <h1 class=\\\"text-center\\\">Projects</h1> <div class=\\\"divider text-center\\\" data-content=\\\"Custom Project Fields\\\"></div> <button if.bind=\\\"program.id && program.projectSchema.length\\\" click.delegate=\\\"batchEditFields()\\\" mdc-button raised>Batch Edit</button> <label class=\\\"checkbox-label\\\"> <mdc-checkbox checked.bind=\\\"jsonEditor\\\"></mdc-checkbox> <span class=\\\"pr-4\\\">Show Advanced Editor</span> </label> <field-edit-list if.bind=\\\"!jsonEditor\\\" fields.two-way=\\\"program.projectSchema\\\"></field-edit-list> <div if.bind=\\\"jsonEditor\\\"> <mdc-json-field value.two-way=\\\"program.projectSchema\\\"></mdc-json-field> </div> <div class=\\\"divider text-center\\\" data-content=\\\"Default Project Filter\\\"></div> <p>Apply a default filter to project data.</p> <button mdc-button raised click.delegate=\\\"buildQuery()\\\"> <mdc-icon>filter_alt</mdc-icon> Edit filter </button> <label class=\\\"checkbox-label\\\"> <mdc-checkbox checked.bind=\\\"jsonEditor2\\\"></mdc-checkbox> <span class=\\\"pr-4\\\">Show Advanced Editor</span> </label> <div> <mdc-json-field if.bind=\\\"jsonEditor2\\\" value.two-way=\\\"program.projectQuery\\\"></mdc-json-field> </div> <div class=\\\"text-center mb-4\\\"> <button class=\\\"button--raised--secondary mt-3\\\" mdc-button raised click.trigger=\\\"save()\\\">Save</button> </div> </div> </template> \";\n// Exports\nmodule.exports = code;","import { autoinject } from 'aurelia-framework';\nimport { ProgramSurvey } from '../../../types/ProgramSurvey';\nimport { AppConfig } from '../../../services/util/AppConfig';\n\nexport interface serviceTable  {\n    title: string,\n    service: string,\n    id: number,\n}\n\n@autoinject\nexport class ShareData {\n    url: string;\n    programId: number;\n    serviceTable: serviceTable[] = [\n        {\n            title: 'Projects',\n            service: 'projectFeatures',\n            id: 0,\n        },\n        {\n            title: 'Project Files',\n            service: 'photoFeatures',\n            id: 0,\n        },\n    ];\n\n    constructor(\n        private config: AppConfig,\n    ){}\n\n    async activate(params, config) {\n        this.programId = config.settings.programId;\n\n        this.url = this.config?.API_HOST;\n\n        config.settings.program.surveys.forEach((survey: ProgramSurvey) => {\n            if (survey.survey_type === 'dfp-form') {\n                this.serviceTable.push({\n                    title: survey.title,\n                    service: survey.survey_type,\n                    id: survey.id,\n                });\n            }\n        });\n    }\n}\n","// Module\nvar code = \"<template> <require from=\\\"components/admin/admin-table\\\"></require> <h1 class=\\\"text-center\\\">Share Data</h1> <mdc-data-table class=\\\"w-100\\\"> <table> <thead> <th>Title</th> <th>Service</th> <th>Service ID</th> <th>Endpoint for ArcGIS</th> </thead> <tbody> <tr mdc-data-table-row repeat.for=\\\"s of serviceTable\\\"> <td>${s.title}</td> <td>${s.service}</td> <td>${s.id}</td> <td if.bind=\\\"s.service === 'dfp-form'\\\"> ${url}/arcgis/rest/services/program-${programId}/surveys/FeatureServer/${s.id} </td> <td if.bind=\\\"s.service === 'projectFeatures'\\\"> ${url}/arcgis/rest/services/program-${programId}/projectFeatures/FeatureServer/${s.id} </td> <td if.bind=\\\"s.service === 'photoFeatures'\\\"> ${url}/arcgis/rest/services/program-${programId}/photoFeatures/FeatureServer/${s.id} </td> </tr> </tbody> </table> </mdc-data-table> </template> \";\n// Exports\nmodule.exports = code;","import { autoinject, LogManager, PLATFORM } from 'aurelia-framework';\nimport { BindingSignaler } from 'aurelia-templating-resources';\nimport { ProgramSurvey, surveyFields } from '../../../types/ProgramSurvey';\nimport { DatafiProAPI } from '../../../services/api/DatafiProAPI';\nimport { ensureNumber } from '../../../util/numbers/ensureNumber';\nimport { APIFile, DefaultActionData, Field, Option, Program, SurveyItemChoice, SurveyItemField, TSurveyType } from '@wsb_dev/datafi-shared/lib/types';\nimport { ValidationController, ValidationControllerFactory } from 'aurelia-validation';\nimport { AlertService } from '../../../services/util/Alert';\nimport { getExcelJson } from '../../../services/api/hooks/files/getExcelJson';\nimport { xformChoicesSchema, xFormSchema } from '../../../services/api/hooks/files/xform/xformSchema';\nimport { titleize } from '@wsb_dev/datafi-shared/lib/util/strings/titleize';\nimport { updateFields } from '../../../components/programs/program-survey-action-edit/updateFields';\nimport { getFields as getSurveyFields } from '@wsb_dev/datafi-shared/lib/util/surveys/getFields';\nimport { Router } from 'aurelia-router';\nimport { DirtyChecker } from '../../../types/DirtyChecker';\nimport { getFields } from '@wsb_dev/datafi-shared/lib/util/fields/getFields';\nimport { DialogService } from 'aurelia-dialog';\nimport { BatchFieldEdit } from '../batch-field-edit/batch-field-edit';\nimport { generatePath } from '@wsb_dev/datafi-shared/lib/util/files/generatePath';\nimport { ConfirmDialog } from '../../../components/confirm-dialog/confirm-dialog';\nimport { ActionEditDialog } from '../../../components/programs/action-edit-dialog/action-edit-dialog';\n\nPLATFORM.moduleName('./../batch-field-edit/batch-field-edit');\n\nconst logger = LogManager.getLogger('dfp:survey-editor');\nexport interface ISurveyTypeOption {\n    value: TSurveyType;\n    label: string;\n}\n@autoinject\nexport class SurveysEdit extends DirtyChecker {\n    public dirtyProps: string[] = ['survey']\n    programId: number;\n    surveyId: number;\n    survey: ProgramSurvey;\n    program: Program;\n\n    validationController: ValidationController;\n    surveyOptions: Option[] = [];\n    surveyOptionsLoading: boolean;\n\n    constructor(\n        private api: DatafiProAPI,\n        private validationFactory: ValidationControllerFactory,\n        private alerts: AlertService,\n        private router: Router,\n        private dialogService: DialogService,\n        private signaler: BindingSignaler,\n    ) { super(); }\n\n    activate(params, config) {\n        this.surveyId = ensureNumber(params.surveyId);\n        this.programId = ensureNumber(config.settings.programId);\n        return this.updateSurvey();\n    }\n\n    async updateSurvey() {\n\n        this.survey = await (this.surveyId ?\n            this.api.programSurveys.get(this.surveyId).then((result) => this.survey = result as ProgramSurvey) :\n            Promise.resolve(new ProgramSurvey({ program_id: this.programId, active: true, shareToPublic: false })));\n        this.program = await this.api.programs.get(this.programId);\n        this.validationController = this.validationFactory.createForCurrentScope();\n\n        if (this.survey.surveySchema.length) this.handleAttachmentsField();\n        this.updateClones();\n        return this.updateSurveys();\n    }\n\n    handleAttachmentsField() {\n        const attachmentsField = this.survey.surveySchema.find((f) => f.path === 'attachments');\n        if (!attachmentsField) {\n            const attachmentsField = {\n                name: 'attachments',\n                type: 'array',\n                visibility: {\n                    list: false,\n                    filter: false,\n                },\n                label: 'Attachments',\n                path: 'attachments',\n            } as Field;\n            this.survey.surveySchema.unshift(attachmentsField);\n        }\n    }\n\n    batchEditFields() {\n        return this.dialogService.open({\n            viewModel: BatchFieldEdit,\n            model: { model: this.survey.surveySchema },\n        }).whenClosed((result) => {\n            if (result.wasCancelled) {\n                return;\n            }\n            this.survey.surveySchema = [...result.output];\n            this.signaler.signal('fields-update');\n            logger.debug('batch updated fields', this.program);\n        });\n    }\n\n    async updateSurveys() {\n        return this.api.files.find({\n            query: {\n                $path: generatePath({ name: 'form', programId: this.survey.program_id }),\n                $limit: 500,\n            },\n        }).then((files: APIFile[]) => {\n            this.surveyOptions = files.filter((file) => /\\.xlsx?/.test(file.id))\n                .map((f) => {\n                    const fileParts = f.id.split('/');\n                    const name = fileParts[fileParts.length - 1].split('.xml')[0];\n                    return { value: f.id, label: titleize(name) };\n                });\n        });\n    }\n\n    /**\n     * Downloads the list of survey fields configured and reconfigures existing fields\n     * on top of the downloaded list. Its a way to automatically reload the existing\n     * configuration with newly configured fields\n     * @param surveyId\n     * @returns\n     */\n    async refreshSurveyFields() {\n        if (!this.survey.survey_id) {\n            return;\n        }\n\n        let fields: Field[];\n\n        const file = await this.api.files.get(this.survey.survey_id, { $url: false, $limit: 50 });\n        const [formFields, formChoices] = await Promise.all([\n            getExcelJson(file, { sheet: 1, schema: xFormSchema }) as Promise<SurveyItemField[]>,\n            getExcelJson(file, { sheet: 2, schema: xformChoicesSchema }) as Promise<SurveyItemChoice[]>,\n        ]);\n\n        // remove fields that are just blank lines\n        const nonEmptyFields = formFields\n            .filter((field) => !!field.name || !!field.type?.replace(/ +/g, ''));\n\n        // get array of fields converted from the survey spreadsheet\n        const metadata = getSurveyFields(nonEmptyFields as SurveyItemField[], formChoices as SurveyItemChoice[]);\n        fields = [\n            ...surveyFields,\n            {\n                name: 'metadata', type: 'object', fields: metadata, visibility: {\n                    list: false,\n                    filter: false,\n                    edit: true,\n                },\n            },\n        ];\n\n        // if fields are already configured, take the configuration from\n        // existing fields and apply it on top\n        // of the new survey fields so we don't lose the configuration\n        fields = updateFields(fields, this.survey.surveySchema);\n\n        logger.debug('program-survey: fields: ', fields);\n        this.survey = new ProgramSurvey({\n            ...this.survey,\n            surveySchema: getFields(fields),\n        });\n        this.handleAttachmentsField();\n    }\n\n    updateProgramFolders() {\n        const programFolderExists = this.program.fileFolders.find((folder) => folder.value === `surveys-${this.survey.id}`);\n\n        if (!this.survey.addAttachments) {\n            return;\n        }\n\n        if (this.survey.addAttachments && !programFolderExists) {\n            this.program.fileFolders.push(\n                { label: this.survey.title, value: `surveys-${this.survey.id}` },\n            );\n        }\n        return this.api.programs.patch(this.program.id, {\n            fileFolders: this.program.fileFolders,\n        }).then((result) => {\n            Object.assign(this.program, result);\n            logger.debug('updated program', this.program);\n        });\n    }\n\n    submit() {\n        this.survey.survey_type = 'dfp-form';\n        return this.validationController.validate()\n            .then(async (result) => {\n                if (result.valid) {\n                    if (this.survey.id) {\n                        return this.api.programSurveys.patch(this.survey.id, this.survey);\n                    } else {\n                        await this.refreshSurveyFields();\n                        const savedSurvey = await this.api.programSurveys.create(this.survey);\n                        const surveyWithActions = new ProgramSurvey({\n                            ...savedSurvey,\n                        });\n                        return this.api.programSurveys.patch(surveyWithActions.id, surveyWithActions);\n                    }\n                }\n            })\n            .then(async (result) => {\n                this.alerts.create({\n                    label: 'Survey updated',\n                    level: 'success',\n                    dismissable: true,\n                });\n\n                const newSurvey = !this.survey.id;\n                Object.assign(this.survey, result);\n                this.updateClones();\n                this.updateProgramFolders();\n\n                if (newSurvey) {\n                    this.router.navigateToRoute('surveys-edit', { surveyId: result.id });\n                } else {\n                    this.router.navigateToRoute('surveys-list');\n                }\n            }).catch((e) => {\n                this.alerts.create({\n                    label: e.message,\n                    level: 'error',\n                    dismissable: true,\n                });\n            });\n    }\n\n    async openActionDialog(index?: number) {\n        return this.dialogService.open({\n            viewModel: ActionEditDialog,\n            model: {\n                action: (index || index === 0 ? this.survey.actions[index] : { allowOnAll: false, inline: false }) as DefaultActionData,\n                survey: this.survey,\n                program: this.program,\n            },\n        }).whenClosed((result) => {\n            if (result.wasCancelled) {\n                return;\n            }\n            index || index === 0 ? this.editAction(index, result.output) : this.addAction(result.output);\n        });\n    }\n\n    addAction(actionData) {\n        this.survey.actions = [\n            ...this.survey.actions,\n            actionData,\n        ];\n    }\n\n    editAction(index, actionData) {\n        this.survey.actions[index] = actionData;\n        this.survey.actions = [...this.survey.actions];\n    }\n\n    removeAction(index: number) {\n        this.survey.actions?.splice(index, 1);\n    }\n\n    removeActionDialog(index: number) {\n        return this.dialogService.open({\n            viewModel: ConfirmDialog,\n            model: {\n                message: 'Are you sure you want to delete this survey action?',\n                title: 'Confirm Delete',\n            } as Partial<ConfirmDialog>,\n        }).whenClosed((result) => {\n            if (result.wasCancelled) {\n                return;\n            }\n            this.removeAction(index);\n        });\n    }\n\n    getActionTypeString(type: string) {\n        const typeObj = {\n            GenerateCSV: 'Create Spreadsheet (csv)',\n            GeneratePDF: 'Create Document or Report',\n            SaveFile: 'Download File',\n            Query: 'Query data from a service',\n            Populate: 'Enrich/Populate data rows',\n            GenerateKoboURL: 'Open a form',\n            EditDFPForm: 'Open Datafi Pro Form (under development)',\n        };\n        return typeObj[type];\n    }\n\n    getActionScopesString(scopes: string[]) {\n        if (!scopes) return;\n        const scopeLabels = scopes.map((scope) => {\n            switch (scope) {\n            case 'program-surveys': return 'Program Surveys List';\n            case 'project-surveys': return 'Project Surveys List';\n            case 'program-surveys-table': return 'Program Surveys Table';\n            case 'project-surveys-table': return 'Project Surveys Table';\n            case 'surveys-table': return 'All Survey Tables';\n            }\n        }).join(', ');\n        return scopeLabels;\n    }\n\n    cancel() {\n        this.router.navigateToRoute('surveys-list');\n    }\n\n    clearFields() {\n        this.survey.surveySchema = [];\n        this.signaler.signal('fields-update');\n    }\n\n}\n","// Module\nvar code = \"<template> <require from=\\\"../../../components/programs/program-survey-action-edit/program-survey-action-edit\\\"></require> <require from=\\\"../../../components/programs/field-edit-table/field-edit-table\\\"></require> <require from=\\\"../../../components/mdc-json-field/mdc-json-field\\\"></require> <require from=\\\"../../../components/mdc-simple-accordion/mdc-simple-accordion\\\"></require> <div class=\\\"flex-grow-1 d-flex flex-column w-100\\\"> <mdc-tab-bar class=\\\"p-centered p-2 mw-800\\\"> <mdc-tab label=\\\"Details\\\" click.delegate=\\\"active = 'details'\\\" icon=\\\"label\\\"> </mdc-tab> <mdc-tab label=\\\"Fields\\\" click.delegate=\\\"active = 'fields'\\\" icon=\\\"list_alt\\\"> </mdc-tab> <mdc-tab label=\\\"Actions\\\" click.delegate=\\\"active = 'actions'\\\" icon=\\\"touch_app\\\"> </mdc-tab> </mdc-tab-bar> <div if.bind=\\\"!active || active === 'details'\\\" class=\\\"p-centered p-2 w-100 mw-800\\\"> <mdc-text-field outlined class=\\\"mt-8\\\" value.bind=\\\"survey.title & validate\\\" type=\\\"text\\\" label=\\\"Title\\\"> </mdc-text-field> <mdc-text-field-helper-line> <mdc-text-field-helper-text validation>Required</mdc-text-field-helper-text> </mdc-text-field-helper-line> <mdc-text-field outlined class=\\\"mt-8\\\" value.bind=\\\"survey.description & validate\\\" type=\\\"text\\\" label=\\\"Description\\\"> </mdc-text-field> <mdc-text-field-helper-line> <mdc-text-field-helper-text validation>Required</mdc-text-field-helper-text> </mdc-text-field-helper-line> <mdc-text-field outlined class=\\\"mt-8\\\" value.bind=\\\"survey.icon & validate\\\" type=\\\"text\\\" label=\\\"Icon Class \\\"> <mdc-icon if.bind=\\\"survey.icon\\\" mdc-text-field-icon trailing>${survey.icon}</mdc-icon> </mdc-text-field> <mdc-text-field-helper-line> <a href=\\\"https://material.io/resources/icons/?style=baseline\\\" target=\\\"_blank\\\">See Icon Help</a> <mdc-text-field-helper-text validation>Required</mdc-text-field-helper-text> </mdc-text-field-helper-line> <mdc-select fixed outlined class=\\\"mt-8 w-100\\\" value.bind=\\\"survey.addAttachments & validate\\\" label=\\\"Add submitted attachments to Program\\\"> <mdc-list> <mdc-list-item value.bind=\\\"true\\\">Yes</mdc-list-item> <mdc-list-item value.bind=\\\"false\\\">No</mdc-list-item> </mdc-list> </mdc-select> <mdc-select-helper-text validation></mdc-select-helper-text> <mdc-select fixed outlined class=\\\"w-100\\\" value.bind=\\\"survey.groupByArea & validate\\\" label=\\\"Group by program area\\\"> <mdc-list> <mdc-list-item value.bind=\\\"1\\\">Yes</mdc-list-item> <mdc-list-item value.bind=\\\"0\\\">No</mdc-list-item> </mdc-list> </mdc-select> <mdc-select-helper-text validation></mdc-select-helper-text> <mdc-linear-progress if.bind=\\\"surveyOptionsLoading\\\" open.bind=\\\"true\\\"></mdc-linear-progress> <mdc-select if.bind=\\\"surveyOptions.length\\\" value.two-way=\\\"survey.survey_id\\\" label=\\\"Survey\\\" outlined class=\\\"w-100\\\"> <mdc-list> <mdc-list-item repeat.for=\\\"survey of surveyOptions\\\" value=\\\"${survey.value}\\\">${survey.label} </mdc-list-item> </mdc-list> </mdc-select> <mdc-select-helper-text validation></mdc-select-helper-text> <mdc-form-field class=\\\"mb-4 ml-3\\\"> <button mdc-switch selected.bind=\\\"survey.active\\\"></button> <label>Active</label> </mdc-form-field> <mdc-form-field class=\\\"mb-4 ml-3\\\"> <button mdc-switch selected.bind=\\\"survey.shareToPublic\\\"></button> <label>Make Public</label> </mdc-form-field> </div> <div if.bind=\\\"active === 'fields'\\\" class=\\\"p-2 mx-5 d-flex flex-column flex-grow-1\\\"> <div if.bind=\\\"!survey.id\\\"> <p class=\\\"text-bold text-gray d-flex align-center justify-center\\\"> <mdc-icon class=\\\"icon-text\\\" style=\\\"margin-right:-10px\\\">info_outlined</mdc-icon> Please save the survey before refreshing the fields. </p> </div> <div else class=\\\"d-flex flex-column flex-grow-1\\\"> <div class=\\\"my-4\\\"> <button if.bind=\\\"survey.id && survey.survey_id\\\" click.delegate=\\\"refreshSurveyFields(survey.survey_id)\\\" mdc-button raised class=\\\"mr-3\\\">Refresh fields</button> <button if.bind=\\\"survey.id && survey.surveySchema.length\\\" click.delegate=\\\"batchEditFields()\\\" mdc-button outlined>Batch Edit</button> <label class=\\\"checkbox-label\\\"> <mdc-checkbox checked.bind=\\\"jsonEditor\\\"></mdc-checkbox> <span class=\\\"pr-4\\\">Show Advanced Editor</span> </label> <button class=\\\"float-right button--color--danger\\\" if.bind=\\\"survey.id && survey.surveySchema.length\\\" click.delegate=\\\"clearFields()\\\" mdc-button raised>Clear fields</button> </div> <mdc-json-field if.bind=\\\"jsonEditor\\\" value.two-way=\\\"survey.surveySchema\\\"></mdc-json-field> <div if.bind=\\\"!jsonEditor\\\" class=\\\"flex-grow-1 p-relative\\\"> <div class=\\\"absolute-cover\\\"> <field-edit-table fields.two-way=\\\"survey.surveySchema & signal:'fields-update'\\\"></field-edit-table> </div> </div> <p class=\\\"text-bold text-gray d-flex align-center justify-center\\\"> <mdc-icon class=\\\"icon-text\\\" style=\\\"margin-right:-10px\\\">info_outlined</mdc-icon> The order in this table affects the submitted data only, not the order of the fillable form. </p> </div> </div> <div if.bind=\\\"active === 'actions'\\\" class=\\\"p-centered p-2 mx-5 flex-grow-1\\\"> <div if.bind=\\\"!survey.id\\\"> <p class=\\\"text-bold text-gray d-flex align-center justify-center\\\"> <mdc-icon class=\\\"icon-text\\\" style=\\\"margin-right:-10px\\\">info_outlined</mdc-icon> Please save the survey before adding actions. </p> </div> <mdc-data-table else class=\\\"w-100 h-100\\\" sticky-header> <table> <thead> <th> <button mdc-button raised click.trigger=\\\"openActionDialog()\\\"><mdc-icon>add</mdc-icon> New</button> </th> <th>Label</th> <th>Icon</th> <th>Type</th> <th>Display</th> <th>Inline</th> <th>Restricted</th> <th></th> </thead> <tbody> <tr mdc-data-table-row repeat.for=\\\"i of survey.actions.length\\\"> <td> <button class=\\\"button--color--primary\\\" mdc-icon-button click.delegate=\\\"openActionDialog($index)\\\" icon=\\\"edit\\\"> </button> </td> <td>${survey.actions[i].label}</td> <td><mdc-icon>${survey.actions[i].icon}</mdc-icon></td> <td>${getActionTypeString(survey.actions[i].id)}</td> <td>${getActionScopesString(survey.actions[i].scopes)}</td> <td> <mdc-form-field> <button mdc-switch selected.bind=\\\"survey.actions[i].inline\\\"></button> </mdc-form-field> </td> <td> <mdc-form-field> <button mdc-switch selected.bind=\\\"survey.actions[i].allowOnAll\\\"></button> </mdc-form-field> </td> <td> <button class=\\\"button--color--danger\\\" mdc-icon-button click.delegate=\\\"removeActionDialog($index)\\\" icon=\\\"delete\\\"> </button> </td> </tr> </tbody> </table> </mdc-data-table> </div> <div class=\\\"p-centered mt-8 mw-800\\\"> <button class=\\\"button--color--secondary\\\" mdc-button click.trigger=\\\"cancel()\\\">Cancel</button> <button mdc-button raised click.trigger=\\\"submit()\\\" disabled.bind=\\\"!survey.survey_id\\\">Save</button> </div> </div> </template> \";\n// Exports\nmodule.exports = code;","import { Paginated } from '@feathersjs/feathers';\nimport { PLATFORM } from 'aurelia-framework';\nimport { autoinject } from 'aurelia-framework';\nimport { DatafiProAPI } from '../../../services/api/DatafiProAPI';\nimport { AlertService } from '../../../services/util/Alert';\nimport { ProgramSurvey } from '../../../types/ProgramSurvey';\nimport { ensureNumber } from '../../../util/numbers/ensureNumber';\nimport { APIFile, Job } from '@wsb_dev/datafi-shared/lib/types';\nimport { ActionService } from '../../../services/actions/ActionService';\nimport { SaveFileActionData } from '@wsb_dev/datafi-shared/lib/types';\nimport { createCustomEvent } from '../../../util/events/createCustomEvent';\nimport { getReportTemplate } from '@wsb_dev/datafi-shared/lib/util/reports/getReportTemplate';\nimport { IXlsFormJobData } from '@wsb_dev/datafi-shared/lib/types/jobs/XlsFormData';\nimport { getJobResult } from '../../../services/api/util/jobs/getJobresult';\nimport { DialogService } from 'aurelia-dialog';\nimport { SurveysListTemplateDialog } from './surveys-list-template-dialog/surveys-list-template-dialog';\nimport { MDCDelete } from '../../../components/mdc-delete-dialog/mdc-delete-dialog';\nimport { debounced } from '../../../util/decorators/debounced';\nimport { IServiceType, generatePath } from '@wsb_dev/datafi-shared/lib/util/files/generatePath';\nimport { SurveysListAddGeojson } from './surveys-list-add-geojson/surveys-list-add-geojson';\nimport { TourService } from '../../../services/tour/TourService';\n\nPLATFORM.moduleName('./surveys-list-template-dialog/surveys-list-template-dialog');\n\nexport interface IUploadEventDetail {\n    created: APIFile[];\n    removed: APIFile[];\n}\n\n@autoinject\nexport class SurveysList {\n    programId: number;\n    surveys: ProgramSurvey[];\n    files: APIFile[];\n    hideFiles: boolean;\n    jobs: Job<IXlsFormJobData>[] = [];\n\n    searchString: string;\n    filteredFiles: APIFile[];\n    isLoading: boolean;\n    sort: number;\n\n    constructor(\n        private api: DatafiProAPI,\n        private alerts: AlertService,\n        private actionService: ActionService,\n        private element: Element,\n        private dialogService: DialogService,\n        private tourDriver: TourService,\n    ) { }\n\n    activate(params, config) {\n        this.sort = -1;\n        this.programId = ensureNumber(config.settings.programId);\n        this.updateSurveys();\n        this.updateFiles();\n    }\n\n    attached() {\n        this.tourDriver.setTour('surveysSettingsTour');\n    }\n\n    detached() {\n        this.tourDriver.setTour();\n    }\n\n    async updateSurveys(): Promise<void>  {\n        return this.api.programSurveys.find({\n            query: {\n                program_id: this.programId,\n                $limit: 50,\n                $sort: { title: 1 },\n            },\n        }).then((result: Paginated<ProgramSurvey>) => {\n            result?.data.forEach((t) => {\n                t.template = getReportTemplate('objects', t.surveySchema || []);\n            });\n            this.surveys = result.data;\n        }).catch((e) => {\n            this.alerts.create({ label: `Error: ${e.message}`, level: 'error', dismissable: true });\n        });\n    }\n\n    async toggleSurveyVisibility(survey: ProgramSurvey): Promise<void> {\n        return this.api.programSurveys.patch(survey.id, { active: survey.active })\n            .then(() => {\n                this.alerts.create({\n                    label: survey.active ? `${survey.title} Active. Save the program to see changes` : `${survey.title} Inactive. Save the program to see changes`,\n                    level: 'success',\n                    dismissable: true,\n                });\n            }).catch((e) => {\n                this.alerts.create({ label: `Error: ${e.message}`, level: 'error', dismissable: true });\n            });\n    }\n\n    async toggleSurveySharing(survey: ProgramSurvey): Promise<void> {\n        return this.api.programSurveys.patch(survey.id, { shareToPublic: survey.shareToPublic })\n            .then(() => {\n                this.alerts.create({\n                    label: survey.shareToPublic ? `${survey.title} has been changed to Public` : `${survey.title} has been changed to Private`,\n                    level: 'success',\n                    dismissable: true,\n                });\n            }).catch((e) => {\n                this.alerts.create({ label: `Error: ${e.message}`, level: 'error', dismissable: true });\n            });\n    }\n\n    async updateFiles() {\n        this.files = [];\n        const paths = [];\n        for (const name of ['form', 'template', 'geojson']) {\n            paths.push(generatePath({ name: name as IServiceType, programId: this.programId }) as string);\n        }\n\n        const promises = paths.map(async (path) => {\n            return await this.api.files.find({\n                query: {\n                    $path: path,\n                    $limit: 50,\n                },\n            }).then((result: APIFile[]) => {\n                return result.map((file) => {\n                    let fileType = '';\n                    if (file.id.includes('/forms/')) {\n                        fileType = 'Form';\n                    } else if (file.id.includes('/templates/')) {\n                        fileType = 'Template';\n                    } else {\n                        fileType = 'Geojson';\n                    }\n                    return {\n                        ...file,\n                        path: file.id,\n                        name: file.id.split('/').pop(),\n                        type: fileType.charAt(0).toUpperCase() + fileType.slice(1),\n                    };\n                });\n            });\n        });\n\n        Promise.all(promises).then((results) => {\n            this.files = results.reduce((a,b) => a.concat(b));\n            this.searchFiles();\n        });\n    }\n\n    delete(survey: ProgramSurvey) {\n        return this.dialogService.open({\n            viewModel: MDCDelete,\n            model: survey,\n        }).whenClosed((result) => {\n            if (result.wasCancelled) {\n                return;\n            }\n\n            this.api.programSurveys\n                .remove(survey.id)\n                .then(() => {\n                    this.alerts.create({ label: 'Survey removed', dismissable: true });\n                    this.updateSurveys();\n                })\n                .catch((e) =>\n                    this.alerts.create({\n                        label: e.data?.table === 'form_submissions' ? 'Form data exists on this survey. Cannot delete. Toggle to Inactive to hide survey.' : e.message,\n                        level: 'error',\n                        dismissable: true,\n                    }),\n                );\n        });\n    }\n\n    //for file list\n    downloadFile(file: APIFile): void {\n        const fileParts = file.id.split('/');\n        this.actionService.create({\n            id: 'SaveFile',\n            target: [file],\n            name: fileParts[fileParts.length - 1],\n        } as SaveFileActionData);\n    }\n\n    deleteFile(file: APIFile): Promise<void> {\n        return this.dialogService.open({\n            viewModel: MDCDelete,\n            model: file,\n        }).whenClosed((result) => {\n            if (result.wasCancelled) {\n                return;\n            }\n\n            this.api.files.remove(file.id).then(() => {\n                this.alerts.create({\n                    label: 'File removed',\n                    dismissable: true,\n                });\n\n                this.element.dispatchEvent(\n                    createCustomEvent(\n                        'removed',\n                        {\n                            created: [],\n                            removed: [file],\n                        } as IUploadEventDetail,\n                        true,\n                    ),\n                );\n                this.updateFiles();\n            });\n        });\n    }\n\n    openTemplate(survey) {\n        navigator.clipboard.writeText(survey.template)\n            .then(() => {\n                this.alerts.create({\n                    label: 'Form copied',\n                    dismissable: true,\n                });\n            })\n            .catch((e) => {\n                this.alerts.create({\n                    label: `Form could not be copied: ${e}`,\n                    dismissable: true,\n                });\n            });\n        return this.dialogService.open({\n            viewModel: SurveysListTemplateDialog,\n            model: { title: survey.title, template: survey.template },\n        });\n    }\n\n    addGeoJSON(fileId) {\n        return this.dialogService.open({\n            viewModel: SurveysListAddGeojson,\n            model: {\n                file: fileId,\n                surveys: this.surveys,\n            },\n        }).whenClosed(() => {\n            return;\n        });\n    }\n\n    getFileName = (f: File): string => {\n        const fileType = this.getFileType(f.name) as IServiceType;\n        return generatePath({\n            name: fileType,\n            programId: this.programId,\n            fileName: f.name,\n        }) as string;\n    }\n\n    addFileToList = (eventDetail: IUploadEventDetail) => {\n        eventDetail.created.forEach((item) => {\n            if (this.getFileType(item.id) === 'form') {\n                this.publishForm(item);\n            }\n        });\n        this.updateFiles();\n\n    }\n\n    publishForm(item: APIFile) {\n        return this.api.jobs.create({\n            name: 'xform',\n            data: {\n                fileId: item.id,\n            },\n        } as Job<IXlsFormJobData>).then((job: Job<IXlsFormJobData>) => {\n            this.jobs.push(job);\n            return getJobResult(this.api.jobs, job)\n                .then((data) => {\n                    this.alerts.create({\n                        label: 'Form published successfully',\n                        level: 'success',\n                        dismissable: true,\n                    });\n                })\n                .catch((e) => {\n                    this.alerts.create({\n                        label: `Form failed to publish: ${e.message}`,\n                        level: 'error',\n                        timeout: 10000,\n                        dismissable: true,\n                    });\n                });\n        });\n    }\n\n    getFileType = (fileName: string): string => {\n        const fileExt = fileName.split('.').pop();\n        const libreOfficeRegex = /(odt|ods|odp|odg|odf|sxw|sxi|sxc|sxd|stw|stx|sxg|sxm|sxb)$/i;\n\n        if (fileExt === 'xlsx' || fileExt === 'xls' || fileExt === 'xml') {\n            return 'form';\n        }\n\n        if (fileExt === 'geojson' || fileExt === 'json') {\n            return 'geojson';\n        }\n\n        if (libreOfficeRegex.test(fileName)) {\n            return 'template';\n        }\n\n        return 'other';\n    }\n\n    @debounced(200)\n    searchFiles() {\n        this.filteredFiles = [];\n\n        if (this.searchString?.length > 1) {\n            this.filteredFiles = this.files.filter((f) => f.name.toLowerCase().includes(this.searchString.toLowerCase()));\n        } else {\n            this.filteredFiles = this.files;\n        }\n        return this.filteredFiles;\n    }\n\n    handleSort(): void {\n        this.sort === 1 ? this.sort = -1 : this.sort = 1;\n\n        this.filteredFiles.sort(\n            (a: { name: string }, b: { name: string }) => {\n                const nameA = (a.name || '').toUpperCase();\n                const nameB = (b.name || '').toUpperCase();\n\n                if (this.sort === 1) {\n                    // asc, arrow up\n                    if (nameA < nameB) { return -1; }\n                    if (nameA > nameB) { return 1; }\n                    return 0;\n                } else {\n                    // desc, arrow down\n                    if (nameA > nameB) { return -1; }\n                    if (nameA < nameB) { return 1; }\n                    return 0;\n                }\n            },\n        );\n    }\n}\n","import { APIFile } from '@wsb_dev/datafi-shared/lib/types/File';\nimport { DialogController } from 'aurelia-dialog';\nimport { autoinject, PLATFORM } from 'aurelia-framework';\nimport { DatafiProAPI } from '../../../../services/api/DatafiProAPI';\nimport { ProgramSurvey } from '../../../../types/ProgramSurvey';\nimport { dataUriToBlob } from '../../../../services/api/hooks/files/dataUriToBlob';\nimport { AlertService } from '../../../../services/util/Alert';\nimport { flattenFields } from '@wsb_dev/datafi-shared/lib/util/surveys/flattenFields';\nimport { Field } from '@wsb_dev/datafi-shared/lib/types';\nimport { v4 as uuidv4 } from 'uuid';\nimport pThrottle from 'p-throttle';\n\nPLATFORM.moduleName('../surveys-list-add-geojson/surveys-list-add-geojson');\n\nexport interface IMapToSurveyField {\n    surveyField: Field;\n    geojsonField: string;\n}\n\n@autoinject\nexport class SurveysListAddGeojson {\n    surveys: ProgramSurvey[];\n    survey: ProgramSurvey;\n    surveyFields: Field[];\n    mappedField: IMapToSurveyField[] = [];\n    geojsonData: Record<string, any>;\n\n    pending: boolean;\n    progress: string;\n\n    constructor(\n        private dialogController: DialogController,\n        private api: DatafiProAPI,\n        private alerts: AlertService,\n    ) { }\n\n    activate(model: { file: string, surveys: ProgramSurvey[] }) {\n        this.surveys = model.surveys;\n        this.getGeoJSONFields(model.file);\n    }\n\n    flattenFields() {\n        this.surveyFields = flattenFields(this.survey.surveySchema);\n        this.surveyFields = this.surveyFields.filter((field) => {\n            const pathsToRemove = [\n                'metadata.survey_id',\n                'metadata.project_id',\n                'metadata.username',\n                'metadata.username',\n                'metadata.userId',\n                'metadata.email',\n                'metadata.program_id',\n            ];\n            return field.path.includes('metadata.') // only include fields with metadata paths\n                && !pathsToRemove.includes(field.path) // remove specific paths\n                && field.type === 'text';// only show fields that are visible in table\n        });\n    }\n\n    async getGeoJSONFields(id) {\n        const result = await this.api.files.get(id, { $url: false }) as APIFile;\n        const blob = dataUriToBlob(result.uri as string);\n        this.geojsonData = await blob.text().then((result) => {\n            const parseJSON = JSON.parse(result);\n\n            for (let i = 0; i < parseJSON.features.length; i++) {\n                parseJSON.features[i].geometry.coordinates = parseJSON.features[i].geometry.coordinates.slice(0, 2);\n            }\n            return parseJSON;\n        }).catch((e) => {\n            this.alerts.create({\n                label: `Could not fetch data ${e}`,\n                level: 'error',\n                timeout: 8000,\n                dismissable: true,\n            });\n        });\n    }\n\n    mapToSurveyField(selection: IMapToSurveyField) {\n        const isMapped = this.mappedField?.some((field) => field.geojsonField === selection.geojsonField);\n\n        if (!selection.surveyField) { // undefined survey field\n            this.mappedField = this.mappedField?.filter((field) => field.geojsonField === selection.geojsonField);\n            return;\n        }\n\n        if (isMapped) { // if a selection has already been made, replace prop value\n            const field = this.mappedField.find((field) => field.geojsonField === selection.geojsonField);\n            Object.assign(field, selection);\n        } else { // If field selection hasn't been made, add new property & value\n            this.mappedField.push(selection);\n        }\n    }\n\n    async submit(): Promise<void> {\n        if (!this.survey || !this.geojsonData) {\n            return;\n        }\n        const throttle = pThrottle({\n            limit: 3,\n            interval: 1000,\n        });\n\n        Promise.all(\n            this.geojsonData.features.map(async (f, i) => {\n                this.pending = true;\n                const metadataObj = this.mappedField.length ? this.buildMetadataObj(f) : { metadata: {} };\n                Object.assign(metadataObj['metadata'], {\n                    program_id: this.survey.program_id,\n                    survey_id: this.survey.id,\n                    username: this.api.auth.me.username,\n                    fullname: this.api.auth.me.fullname,\n                });\n\n                const throttled = throttle(() => {\n                    this.progress = (i / this.geojsonData.features.length * 100).toFixed();\n                    return this.api.formSubmissions.create({\n                        survey_id: this.survey.id,\n                        instance_id: uuidv4(),\n                        geom: f.geometry,\n                        program_id: this.survey.program_id,\n                        ...metadataObj,\n                        attachments: [],\n                    }).catch((e) => {\n                        this.pending = false;\n                        this.alerts.create({\n                            label: `Geojson was not created: ${e}`,\n                            level: 'error',\n                            timeout: 8000,\n                            dismissable: true,\n                        });\n                        return this.dialogController.ok();\n                    });\n                });\n                await throttled();\n            }),\n        ).then(() => {\n            this.pending = false;\n            this.alerts.create({\n                label: `${this.geojsonData.features.length} Records added successfully`,\n                level: 'success',\n                timeout: 8000,\n                dismissable: true,\n            });\n            this.dialogController.ok();\n        });\n    }\n\n    buildMetadataObj(feature) {\n        const output = {};\n        let current = {};\n        for (const path of this.mappedField) {\n            current = output;\n            for (const segment of path.surveyField.path.split('.')) {\n                if (!(segment in current)) {\n                    if (path.surveyField.path.split('.').length - 1 === path.surveyField.path.split('.').indexOf(segment)) {\n                        current[segment] = feature.properties[path.geojsonField] ? feature.properties[path.geojsonField] : undefined;\n                    } else {\n                        current[segment] = {};\n                    }\n                }\n                current = current[segment];\n            }\n        }\n        return output;\n    }\n}\n","// Module\nvar code = \"<template> <ux-dialog class=\\\"survey-list-add-geojson\\\"> <ux-dialog-header> <h3 class=\\\"align-header\\\">ADD GEOJSON DATA</h3> <button class=\\\"button--color--secondary float-right\\\" icon=\\\"close\\\" mdc-icon-button click.trigger=\\\"dialogController.cancel()\\\"></button> </ux-dialog-header> <ux-dialog-body style=\\\"width:700px\\\"> <mdc-select value.bind=\\\"survey\\\" label=\\\"Choose a Survey\\\" fixed outlined class=\\\"w-100\\\" mdcselect:change.delegate=\\\"flattenFields(survey.id)\\\"> <mdc-list> <mdc-list-item repeat.for=\\\"s of surveys\\\" value.bind=\\\"s\\\">${s.title} </mdc-list-item> </mdc-list> </mdc-select> <div class=\\\"my-2\\\" if.bind=\\\"!geojsonData\\\">Invalid GeoJSON. Please check data and upload again</div> <div if.bind=\\\"survey && geojsonData\\\" class=\\\"mt-10\\\"> <mdc-data-table class=\\\"w-100 custom-table\\\"> <table> <thead> <th>${geojsonData.name} <span class=\\\"text-italic\\\"> (sample data)</span></th> <th>${survey.title}</th> </thead> <tbody> <tr mdc-data-table-row repeat.for=\\\"g of geojsonData.features[0].properties | keys\\\"> <td> <strong>${g}</strong>:<span class=\\\"text-italic\\\"> ${geojsonData.features[0].properties[g] ? geojsonData.features[0].properties[g] : 'null'}</span> </td> <td> <mdc-select naturalWidth fixed mdcselect:change.delegate=\\\"mapToSurveyField(nameSelection)\\\" value.bind=\\\"nameSelection\\\" label=\\\"Field\\\" class=\\\"survey-select\\\"> <mdc-list> <mdc-list-item value.bind=\\\"{surveyField: undefined, geojsonField: undefined}\\\"></mdc-list-item> <mdc-list-item repeat.for=\\\"field of surveyFields\\\" value.bind=\\\"{surveyField: field, geojsonField: g}\\\">${field.label} (${field.path}) </mdc-list-item> </mdc-list> </mdc-select> </td> </tr> </tbody> </table> </mdc-data-table> </div> </ux-dialog-body> <ux-dialog-footer> <button class=\\\"button--color--secondary float-left\\\" mdc-button click.trigger=\\\"dialogController.cancel()\\\">Cancel</button> <button attach-focus mdc-button raised disabled.bind=\\\"!survey || !geojsonData\\\" click.trigger=\\\"submit()\\\"> <mdc-circular-progress class=\\\"mdc-circular-progress__white mr-2\\\" size=\\\"25\\\" if.bind=\\\"pending\\\" stroke-width=\\\"3\\\"></mdc-circular-progress> ${progress} ${pending ? '% processed' : 'submit'} </button> </ux-dialog-footer> <div class=\\\"mdc-dialog__scrim\\\"></div> </ux-dialog> </template>\";\n// Exports\nmodule.exports = code;","import { DialogController } from 'aurelia-dialog';\nimport { inject } from 'aurelia-framework';\n\n@inject(DialogController)\nexport class SurveysListTemplateDialog {\n\n    title: string;\n    bodyText: string;\n\n    constructor(\n        private dialogController: DialogController,\n    ) { }\n\n    activate(model){\n\n        this.title = model.title;\n        this.bodyText = model.template;\n\n    }\n}\n","// Module\nvar code = \"<template> <ux-dialog> <ux-dialog-body style=\\\"width:700px\\\" class=\\\"text-center\\\"> <h4> ${title} Template </h4> <div style=\\\"max-height:400px;background-color:#fafafa\\\"> <mdc-text-field textarea=\\\"true\\\" outlined=\\\"true\\\" value.bind=\\\"bodyText\\\" rows=\\\"10\\\" cols=\\\"100\\\"> </mdc-text-field> </div> </ux-dialog-body> <ux-dialog-footer class=\\\"text-center\\\"> <button attach-focus mdc-button type=\\\"button\\\" class=\\\"button--color--secondary\\\" click.delegate=\\\"dialogController.cancel()\\\"> Close </button> </ux-dialog-footer> <div class=\\\"mdc-dialog__scrim\\\"></div> </ux-dialog> </template> \";\n// Exports\nmodule.exports = code;","// Module\nvar code = \"<template> <require from=\\\"../../../components/mdc-upload-field/mdc-upload-field\\\"></require> <h1 class=\\\"text-center\\\">Surveys</h1> <div> <a route-href=\\\"route: surveys-edit; params.bind: {surveyId: 0}\\\" raised mdc-button class=\\\"mb-3\\\" data-tour-id=\\\"program-survey-create\\\"> <mdc-icon>add</mdc-icon>Create New </a> </div> <mdc-data-table class=\\\"w-100\\\" data-tour-id=\\\"program-survey-list\\\"> <table> <thead> <th></th> <th>Title</th> <th>ID</th> <th>XLSX Form</th> <th>ODT Template</th> <th>Active</th> <th>Make Public</th> <th></th> </thead> <tbody> <tr mdc-data-table-row repeat.for=\\\"survey of surveys\\\"> <td data-tour-id=\\\"survey-settings-edit\\\"> <a route-href=\\\"route: surveys-edit; params.bind: {surveyId: survey.id}\\\" mdc-icon-button class=\\\"button--color--primary\\\" icon=\\\"edit\\\"> </a> </td> <td>${survey.title}</td> <td>${survey.id}</td> <td> <div repeat.for=\\\"file of filteredFiles\\\" if.bind=\\\"file.id === survey.survey_id\\\" class=\\\"d-inline-flex justify-center align-center\\\"> <button mdc-icon-button class=\\\"button--color--secondary mr-2\\\" click.trigger=\\\"downloadFile(file)\\\" icon=\\\"download\\\"> </button> ${file.name} </div> </td> <td> <button mdc-icon-button class=\\\"button--color--secondary\\\" click.trigger=\\\"openTemplate(survey)\\\" icon=\\\"description\\\"> </button> </td> <td> <mdc-form-field> <button mdc-switch selected.bind=\\\"survey.active\\\" change.delegate=\\\"toggleSurveyVisibility(survey)\\\"></button> </mdc-form-field> </td> <td data-tour-id=\\\"survey-settings-public\\\"> <mdc-form-field> <button mdc-switch selected.bind=\\\"survey.shareToPublic\\\" change.delegate=\\\"toggleSurveySharing(survey)\\\" data-tour-id=\\\"survey-settings-public\\\"></button> </mdc-form-field> </td> <td> <button class=\\\"button--color--danger\\\" mdc-icon-button click.delegate=\\\"delete(survey)\\\" icon=\\\"delete\\\"> </button> </td> </tr> </tbody> </table> </mdc-data-table> <div class=\\\"text-center mt-3\\\" data-tour-id=\\\"program-survey-upload\\\"> <mdc-upload-field get-file-name.bind=\\\"getFileName\\\" created.delegate=\\\"addFileToList($event.detail)\\\" files.bind=\\\"files\\\" class=\\\"w-100 d-block\\\"> <template replace-part=\\\"file-list\\\"></template> </mdc-upload-field> <mdc-text-field class=\\\"mw-xs mt-3\\\" if.bind=\\\"files.length > 10\\\" outlined value.bind=\\\"searchString\\\" type=\\\"text\\\" label=\\\"Search for a File\\\" placeholder=\\\"Search for a File\\\" input.delegate=\\\"searchFiles()\\\"> </mdc-text-field> </div> <mdc-data-table class=\\\"w-100 mt-3\\\" data-tour-id=\\\"program-survey-files\\\"> <table> <thead> <th></th> <th> <div class=\\\"d-inline-flex justify-center align-center\\\"> Name <button class=\\\"mdc-icon-button material-icons mdc-data-table__sort-icon-button\\\" click.delegate=\\\"handleSort()\\\" aria-label=\\\"Sort Files\\\"> <mdc-icon if.bind=\\\"sort === 1\\\">arrow_upward</mdc-icon> <mdc-icon else>arrow_downward</mdc-icon> </button> </div> </th> <th>Path</th> <th>Type</th> <th></th> </thead> <tbody> <tr mdc-data-table-row repeat.for=\\\"file of filteredFiles\\\"> <td> <a mdc-icon-button click.trigger=\\\"downloadFile(file)\\\"> <mdc-icon>download</mdc-icon> </a> <a mdc-icon-button click.trigger=\\\"addGeoJSON(file.path)\\\" if.bind=\\\"file.type === 'Geojson'\\\"> <mdc-icon>add_location</mdc-icon> </a> </td> <td>${file.name}</td> <td>${file.path}</td> <td>${file.type}</td> <td> <button class=\\\"button--color--danger\\\" mdc-icon-button click.delegate=\\\"deleteFile(file)\\\"> <mdc-icon>delete</mdc-icon> </button> </td> </tr> </tbody> </table> </mdc-data-table> </template>\";\n// Exports\nmodule.exports = code;","import { autoinject, bindable, LogManager } from 'aurelia-framework';\nimport { Program } from '../../../types/Program';\nimport { debounced } from '../../../util/decorators/debounced';\nimport { DatafiProAPI } from '../../../services/api/DatafiProAPI';\nimport { Router } from 'aurelia-router';\nimport { recursiveQuery } from '../../../util/query/recursive';\nimport { Paginated, Params } from '@feathersjs/feathers';\nimport { ValidatedRole } from '../../../types/Roles';\nimport { ValidatedUser } from '../../../types/Users';\nimport { AlertService } from '../../../services/util/Alert';\nimport { ValidatedOrganization } from '../../../types/Organizations';\nimport { BaseModel, Organization } from '@wsb_dev/datafi-shared/lib/types';\nimport { userHasPermission } from '@wsb_dev/datafi-shared/lib/util/users/userHasPermission';\nconst log = LogManager.getLogger('dfp:users-edit');\n\nexport interface ColumnList {\n    name: string;\n    active?: boolean;\n    id?: number;\n    sort: boolean;\n}\n@autoinject\nexport class UsersEdit {\n    @bindable rows: BaseModel[];\n    @bindable newUserList: BaseModel[];\n    @bindable params: Params;\n    @bindable orgs: ValidatedOrganization[];\n    licenseCount: number;\n    licenseStatusClass: string;\n\n    sort = 1;\n    currentSortColumn = 'Name';\n\n    programId: number;\n    program: Program;\n    organization: Organization;\n    usersLoading: boolean;\n    appRoles: ValidatedRole[];\n    users: ValidatedUser[];\n    searchString: string;\n    columnList = [\n        {\n            name: 'Last Active',\n            sort: true,\n        },\n        {\n            name: 'Name',\n            sort: true,\n        },\n        {\n            name: 'Username',\n            sort: true,\n        },\n        {\n            name: 'Role',\n            active: false,\n            id: undefined,\n            sort: false,\n        },\n        {\n            name: 'Organizations',\n            active: false,\n            id: undefined,\n            sort: false,\n        },\n    ] as ColumnList[];\n\n    constructor(\n        private api: DatafiProAPI,\n        private router: Router,\n        private alerts: AlertService,\n    ) { }\n\n    async activate(params: { id: string }): Promise<void> {\n        this.programId = parseInt(params.id, 10);\n\n        this.params = {\n            $eager: 'user',\n            program_id: this.programId,\n        };\n        this.refresh();\n    }\n\n    async refresh(): Promise<void> {\n        await this.updateAppRoles();\n        await this.updateProgram();\n        if (this.organization?.license_limit) await this.updateLicenseCount();\n        await this.updateUsers();\n    }\n\n    async updateAppRoles(): Promise<void> {\n        const appRoles = (await this.api.roles.find({\n            query: {\n                scopes: { $contains: '[\"program\"]' },\n            },\n        })) as Paginated<ValidatedRole>;\n        this.appRoles = appRoles.data;\n    }\n\n    @debounced(100)\n    async updateProgram(): Promise<void> {\n        if (this.program) {\n            this.program.destroy();\n        }\n        this.program = this.programId\n            ? await this.api.programs\n                .get(this.programId, {\n                    query: {\n                        $eager: '[assetTypes, configs, surveys, roles.role]',\n                    },\n                })\n                .then((result) => new Program(result, this.api.files))\n                .catch((e) => undefined)\n            : new Program({}, this.api.files);\n\n        if (!this.program) {\n            this.router.navigateToRoute('home');\n        }\n\n        if (this.program.managementOrganizationId) {\n            this.organization = await this.api.organizations.get(this.program.managementOrganizationId);\n        }\n    }\n\n    async updateLicenseCount(): Promise<void> {\n        await this.api.programUsersRoles.find({\n            query: {\n                program_org_id: this.organization.id,\n                $eager: 'user',\n                $joinRelation: 'user',\n                $limit: 5000,\n            },\n        }).then((result: any) => {\n            this.licenseCount = result.data.filter((value, index, array) => {\n                return !value.user.licenseExempt && array.findIndex((v) => v.user_id === value.user_id) === index;\n            }).length;\n            const licenseRatio = this.licenseCount / this.organization.license_limit;\n            this.licenseStatusClass = licenseRatio >= 0.75 && licenseRatio < 0.9 ? 'text-warning' :\n                licenseRatio >= 0.9 ? 'text-error' : '';\n        }).catch((e) => {\n            this.alerts.create({\n                label: e.message,\n                level: 'error',\n                dismissable: true,\n            });\n        });\n    }\n\n    async updateUsers(): Promise<void> {\n        this.usersLoading = true;\n\n        const query = {\n            $limit: 50,\n        };\n        if (!userHasPermission(this.api.auth.me, '*', '*')) {\n            const accessibleOrgs: number[] = this.api.auth.me.organizationId === this.organization?.id ?\n                [0, this.organization.id, ...this.organization.partner_orgs] :\n                [this.api.auth.me.organizationId];\n            query['organizationId'] = { $in: accessibleOrgs };\n        }\n\n        if (this.organization?.license_limit && this.licenseCount >= this.organization?.license_limit) {\n            return this.api.programUsersRoles.find({\n                query: {\n                    ...query,\n                    program_org_id: this.organization.id,\n                    $eager: 'user',\n                    $joinRelation: 'user',\n                },\n            }).then((result: any) => {\n                this.users = result.data.filter((value, index, array) => {\n                    return array.findIndex((v) => v.user_id === value.user_id) === index;\n                }).map((u) => new ValidatedUser(u.user, this.api.files));\n            }).catch((e) => {\n                this.alerts.create({\n                    label: e.message,\n                    level: 'error',\n                    dismissable: true,\n                });\n            });\n        }\n\n        return recursiveQuery(this.api.users, query, [])\n            .then((result: any) => {\n                this.users = result.map((u) => new ValidatedUser(u, this.api.files));\n            })\n            .finally(() => (this.usersLoading = false));\n    }\n\n    async rowsChanged(): Promise<void> {\n        const orgList = Array.from(\n            new Set(this.rows.map((user) => user.user.organizationId).filter((id) => id !== undefined)),\n        );\n        this.orgs = await this.api.organizations.find({ query: { $limit: 50, id: { $in: orgList } } }).then((orgs: ValidatedOrganization) => orgs.data);\n\n        this.newUserList = this.rows.map((row) => {\n            const orgName = this.orgs.find((org) => org.id === row?.user.organizationId);\n            const appRole = this.appRoles.find((role) => role.id === row.role_id);\n            return {\n                ...row,\n                org_name: orgName?.name,\n                role_name: appRole?.role_name,\n            };\n        });\n    }\n\n    sortUsers(column: string): void {\n        if (this.currentSortColumn !== column) {\n            this.sort = -1;\n            this.currentSortColumn = column;\n        } else {\n            this.sort = this.sort === 1 ? -1 : 1;\n        }\n\n        this.newUserList.sort((a, b) => {\n            let valueA, valueB;\n\n            switch (column) {\n            case 'Name':\n                valueA = (a.user.fullname || '').toUpperCase();\n                valueB = (b.user.fullname || '').toUpperCase();\n                break;\n            case 'Username':\n                valueA = (a.user.username || '').toUpperCase();\n                valueB = (b.user.username || '').toUpperCase();\n                break;\n            case 'Last Active':\n                valueA = new Date(a.user.updatedAt).getTime();\n                valueB = new Date(b.user.updatedAt).getTime();\n                break;\n            default:\n                return 0;\n            }\n\n            if (valueA < valueB) return this.sort === 1 ? -1 : 1;\n            if (valueA > valueB) return this.sort === 1 ? 1 : -1;\n            return 0;\n        });\n    }\n\n    async updateUserRole(role_name: string, user: ValidatedUser): Promise<void> {\n        const newRole = this.appRoles.find((r) => r.role_name === role_name);\n\n        const roleToUpdate = this.program.roles.find((r) => {\n            return r.id === user.id;\n        });\n        await this.api.programUsersRoles.patch(roleToUpdate.id, { role_id: newRole.id }).catch((e) => {\n            this.alerts.create({\n                label: e.message,\n                level: 'error',\n                dismissable: true,\n            });\n        });\n        await this.api.programs.patch(this.program.id, this.program);\n        await this.refresh();\n        this.params = { ...this.params };\n\n        this.alerts.create({\n            label: 'User role changed.',\n            level: 'success',\n            dismissable: true,\n        });\n    }\n\n    async addUser(user: ValidatedUser, role: number): Promise<void> {\n        if (!user || !role) {\n            return this.alerts.create({\n                label: 'Please select a user and role.',\n                level: 'warning',\n                dismissable: true,\n            });\n        }\n        await this.refresh();\n        this.params = { ...this.params };\n\n        const roleToAdd = this.appRoles.find((r) => r.id === role);\n        const existingRole = this.program.roles.find((r) => r.user_id === user.id);\n\n        if (existingRole) {\n            return this.alerts.create({\n                label: 'User exists in table',\n                level: 'warning',\n                dismissable: true,\n            });\n        }\n\n        await this.api.programUsersRoles.create({\n            role_id: roleToAdd.id,\n            user_id: user.id,\n            program_id: this.program.id,\n            organizationId: user?.organizationId ? user.organizationId : 0,\n            program_org_id: this.program.managementOrganizationId,\n        }).catch((e) => {\n            this.alerts.create({\n                label: e.message,\n                level: 'error',\n                dismissable: true,\n            });\n        });\n        await this.api.programs.patch(this.program.id, this.program);\n        await this.refresh();\n        this.params = { ...this.params };\n\n        this.alerts.create({\n            label: 'Role added.',\n            level: 'success',\n            dismissable: true,\n        });\n    }\n\n    async removeUser(userId: number): Promise<void> {\n        const roleToRemove = this.program.roles.find((r) => {\n            return r.user_id === userId;\n        });\n\n        await this.api.programUsersRoles.remove(roleToRemove.id).catch((e) => {\n            this.alerts.create({\n                label: e.message,\n                level: 'error',\n                dismissable: true,\n            });\n        });\n        await this.api.programs.patch(this.program.id, this.program);\n        await this.refresh();\n        this.params = { ...this.params };\n\n        this.alerts.create({\n            label: 'User removed',\n            level: 'success',\n            dismissable: true,\n        });\n    }\n\n    changeParams(): void {\n        this.params = {\n            ...this.params,\n            $eager: 'user',\n            $joinRelation: 'user',\n            $or: [\n                { 'user.username': { $ilike: '%' + this.searchString + '%' } },\n                { 'user.fullname': { $ilike: '%' + this.searchString + '%' } },\n            ],\n        };\n    }\n\n    filterUsers(filterId?: number, selection?: ColumnList): void {\n        if (selection) {\n            this.columnList.forEach((col) => {\n                if (col.name === selection.name) {\n                    col.id = filterId || filterId === 0 ? filterId : undefined;\n                    col.active = filterId || filterId === 0 ? true : false;\n                }\n            });\n        }\n        const activeColumns = this.columnList.filter((option) => option.active);\n        const org = activeColumns.find((col) => col.name === 'Organizations');\n        const role = activeColumns.find((col) => col.name === 'Role');\n\n        this.params = {\n            ...this.params,\n            role_id: role?.id,\n            organizationId: org?.id,\n        };\n    }\n}\n","// Module\nvar code = \"<template> <require from=\\\"../../../components/admin/admin-table\\\"></require> <h1 class=\\\"text-center\\\">Users</h1> <div if.bind=\\\"organization.license_limit\\\" class=\\\"d-flex align-center\\\"> <h3 class=\\\"m-0\\\">${organization.name} Licenses: <span class=\\\"${licenseStatusClass}\\\">${licenseCount}/${organization.license_limit}</span> </h3> <p class=\\\"ml-5 text-bold text-gray\\\"> An organization has a limited number of licenses for users.</p> </div> <p if.bind=\\\"licenseCount >= organization.license_limit\\\" class=\\\"text-error d-flex align-center\\\"> <mdc-icon class=\\\"icon-text\\\" style=\\\"margin-right:-10px\\\">info_outlined</mdc-icon> The license limit has been met. You can only add users who already hold a license. </p> <div class=\\\"d-inline-flex w-100 justify-between mt-8 flex-wrap\\\" mdc-menu-surface-anchor> <div class=\\\"d-flex align-center mb-7 w-fit flex-wrap\\\"> <mdc-text-field required class=\\\"mr-3 w-auto\\\" outlined label=\\\"Add User\\\" ref=\\\"userInput\\\"> </mdc-text-field> <mdc-lookup class=\\\"text-left\\\" options.bind=\\\"users\\\" value.bind=\\\"userValue & validateOnChange\\\" icon=\\\"add\\\" input.bind=\\\"userInput\\\" hoist-to-body> </mdc-lookup> <mdc-select class=\\\"mr-3\\\" label=\\\"Select a Role\\\" outlined value.bind=\\\"selectedAppRole\\\" required> <mdc-list> <mdc-list-item value.bind=\\\"a.id\\\" repeat.for=\\\"a of appRoles\\\" class=\\\"text-left\\\"> ${a.role_name | title} </mdc-list-item> </mdc-list> </mdc-select> <button mdc-button raised click.delegate=\\\"addUser(userValue, selectedAppRole)\\\" class=\\\"p-3 mr-3\\\"> Add </button> </div> <mdc-text-field outlined class=\\\"mw-xs mb-7\\\" value.bind=\\\"searchString\\\" type=\\\"text\\\" label=\\\"Search for a User\\\" input.delegate=\\\"changeParams()\\\"> </mdc-text-field> </div> <div class=\\\"container h-100 d-flex flex-column\\\"> <div class=\\\"flex-grow-1 mb-2 h-100 p-relative\\\"> <div class=\\\"absolute-cover\\\"> <admin-table params.bind=\\\"params\\\" service.bind=\\\"api.programUsersRoles\\\" rows.two-way=\\\"rows\\\"> <template replace-part=\\\"table\\\"> <mdc-data-table pagination page-sizes.bind=\\\"[10,25,50]\\\" page-size.two-way=\\\"perPage\\\" records-count.bind=\\\"total\\\" active-page.bind=\\\"page\\\" class=\\\"admin h-100\\\" busy.bind=\\\"busy\\\" mdcdatatable:navigation.trigger=\\\"handleNavigation($event.detail.type)\\\"> <table> <thead> <th repeat.for=\\\"g of columnList\\\"> <div class=\\\"d-inline-flex justify-center align-center\\\"> <span>${g.name}</span> <div mdc-menu-surface-anchor ref=\\\"roleAnchor\\\" class=\\\"ml-2\\\" if.bind=\\\"!g.sort\\\"> <button class=\\\"button--color--primary\\\" mdc-icon-button click.trigger=\\\"(r.open = !r.open)\\\"> <mdc-icon>${!g.active ? 'filter_alt_off' : 'filter_alt'}</mdc-icon> </button> <mdc-menu anchor-corner=\\\"BOTTOM_LEFT\\\" view-model.ref=\\\"r\\\" anchor.bind=\\\"roleAnchor\\\" hoist-to-body mdcmenu:selected.trigger=\\\"filterUsers($event.detail.data, g)\\\" if.bind=\\\"g.name === 'Role'\\\"> <mdc-list> <mdc-list-item activated.bind=\\\"!g.active\\\">No Filter</mdc-list-item> <mdc-list-item repeat.for=\\\"a of appRoles\\\" value.bind=\\\"a.id\\\" activated.bind=\\\"g.id === a.id\\\"> ${a.role_name | title} </mdc-list-item> </mdc-list> </mdc-menu> <mdc-menu anchor-corner=\\\"BOTTOM_LEFT\\\" view-model.ref=\\\"r\\\" anchor.bind=\\\"roleAnchor\\\" hoist-to-body mdcmenu:selected.trigger=\\\"filterUsers($event.detail.data, g)\\\" if.bind=\\\"g.name === 'Organizations'\\\"> <mdc-list> <mdc-list-item activated.bind=\\\"!g.active\\\">No Filter</mdc-list-item> <mdc-list-item activated.bind=\\\"g.id === o.id\\\" value.bind=\\\"o.id\\\" repeat.for=\\\"o of orgs\\\">${o.name | title} </mdc-list-item> </mdc-list> </mdc-menu> </div> <div else> <button mdc-icon-button class=\\\"mdc-icon-button button--color--primary\\\" click.delegate=\\\"sortUsers(g.name)\\\" aria-label=\\\"Sort by ${g.name}\\\" aria-describedby=\\\"name-status-label\\\" icon=\\\"swap_vert\\\"> </button> </div> </div> </th> <th></th> </thead> <tbody> <tr mdc-data-table-row repeat.for=\\\"r of newUserList\\\"> <td>${r.user.updatedAt | date:'MM/DD/YYYY HH:mm A'}</td> <td> ${r.user.fullname} <mdc-icon class=\\\"icon-text text-gray\\\" style=\\\"margin-right:-10px\\\" mdc-tooltip=\\\"License Exempt User\\\" if.bind=\\\"organization.license_limit && r.user.licenseExempt\\\">info_outlined</mdc-icon> </td> <td>${r.user.username}</td> <td> <mdc-select class=\\\"py-2\\\" change.delegate=\\\"updateUserRole($event.target.value, r)\\\" outlined fixed value.bind=\\\"r.role_name\\\"> <mdc-list> <mdc-list-item value.bind=\\\"a.role_name\\\" repeat.for=\\\"a of appRoles\\\"> ${a.role_name | title} </mdc-list-item> </mdc-list> </mdc-select> </td> <td> <mdc-chip if.bind=\\\"r.user.organizationId > 0\\\"> <button mdc-chip-action icon=\\\"groups\\\"><span class=\\\"ml-2\\\">${r.org_name}</span></button> </mdc-chip> </td> <td> <button mdc-icon-button icon=\\\"cancel\\\" click.trigger=\\\"removeUser(r.user_id)\\\"></button> </td> </tr> </tbody> </table> </mdc-data-table> </template> </admin-table> </div> </div> </div> </template> \";\n// Exports\nmodule.exports = code;"],"sourceRoot":""}