├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── NOTICE ├── README.md ├── _config.yml ├── build.gradle ├── buildSrc ├── build.gradle └── src │ └── main │ └── groovy │ └── de │ └── iteratec │ └── osm │ └── frontendBuild │ └── Grails2FrontendI18nTask.groovy ├── docker ├── README.md ├── docker-compose.yml ├── entrypoint.sh ├── osm-with-wpt │ ├── docker-compose.yml │ └── locations.ini └── templates │ └── osm-config.yml.j2 ├── frontend ├── .editorconfig ├── README.md ├── angular.json ├── package-lock.json ├── package.json ├── src │ ├── app │ │ ├── app-routing.module.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── enums │ │ │ ├── chart-commons.enum.ts │ │ │ ├── color-scheme.enum.ts │ │ │ ├── performance-aspect-types.enum.ts │ │ │ ├── ui-component.enum.ts │ │ │ ├── unit.enum.ts │ │ │ └── url.enum.ts │ │ ├── global.module.spec.ts │ │ ├── global.module.ts │ │ ├── models │ │ │ ├── application-csi.model.ts │ │ │ ├── application.model.ts │ │ │ ├── browser.model.ts │ │ │ ├── connectivity.model.ts │ │ │ ├── csi.model.ts │ │ │ ├── global-osm-namespace.model.ts │ │ │ ├── loading.model.ts │ │ │ ├── location.model.ts │ │ │ ├── measurand.model.ts │ │ │ ├── measured-event.model.ts │ │ │ ├── page.model.ts │ │ │ ├── perfomance-aspect.model.ts │ │ │ └── response-with-loading-state.model.ts │ │ ├── modules │ │ │ ├── aggregation │ │ │ │ ├── aggregation.component.html │ │ │ │ ├── aggregation.component.scss │ │ │ │ ├── aggregation.component.spec.ts │ │ │ │ ├── aggregation.component.ts │ │ │ │ ├── aggregation.module.ts │ │ │ │ ├── components │ │ │ │ │ └── aggregation-chart │ │ │ │ │ │ ├── aggregation-chart.component.html │ │ │ │ │ │ ├── aggregation-chart.component.scss │ │ │ │ │ │ ├── aggregation-chart.component.spec.ts │ │ │ │ │ │ └── aggregation-chart.component.ts │ │ │ │ ├── models │ │ │ │ │ ├── aggregation-chart-data.model.ts │ │ │ │ │ ├── aggregation-chart-series.model.ts │ │ │ │ │ └── get-barchart-command.model.ts │ │ │ │ └── services │ │ │ │ │ ├── aggregation-chart-data.service.spec.ts │ │ │ │ │ ├── aggregation-chart-data.service.ts │ │ │ │ │ ├── barchart-data.service.spec.ts │ │ │ │ │ └── barchart-data.service.ts │ │ │ ├── application-dashboard │ │ │ │ ├── application-dashboard.component.html │ │ │ │ ├── application-dashboard.component.scss │ │ │ │ ├── application-dashboard.component.spec.ts │ │ │ │ ├── application-dashboard.component.ts │ │ │ │ ├── application-dashboard.module.spec.ts │ │ │ │ ├── application-dashboard.module.ts │ │ │ │ ├── components │ │ │ │ │ ├── application-job-status │ │ │ │ │ │ ├── application-job-status.component.html │ │ │ │ │ │ ├── application-job-status.component.scss │ │ │ │ │ │ ├── application-job-status.component.spec.ts │ │ │ │ │ │ ├── application-job-status.component.ts │ │ │ │ │ │ └── graphite-integration │ │ │ │ │ │ │ ├── graphite-integration.component.html │ │ │ │ │ │ │ ├── graphite-integration.component.scss │ │ │ │ │ │ │ ├── graphite-integration.component.spec.ts │ │ │ │ │ │ │ └── graphite-integration.component.ts │ │ │ │ │ ├── application-select │ │ │ │ │ │ ├── application-select.component.html │ │ │ │ │ │ ├── application-select.component.scss │ │ │ │ │ │ ├── application-select.component.spec.ts │ │ │ │ │ │ └── application-select.component.ts │ │ │ │ │ ├── csi-graph │ │ │ │ │ │ ├── csi-graph.calculator.ts │ │ │ │ │ │ ├── csi-graph.component.html │ │ │ │ │ │ ├── csi-graph.component.scss │ │ │ │ │ │ ├── csi-graph.component.spec.ts │ │ │ │ │ │ └── csi-graph.component.ts │ │ │ │ │ ├── csi-info │ │ │ │ │ │ ├── csi-info.component.html │ │ │ │ │ │ ├── csi-info.component.scss │ │ │ │ │ │ ├── csi-info.component.spec.ts │ │ │ │ │ │ └── csi-info.component.ts │ │ │ │ │ ├── page-metric │ │ │ │ │ │ ├── page-metric.component.html │ │ │ │ │ │ ├── page-metric.component.scss │ │ │ │ │ │ ├── page-metric.component.spec.ts │ │ │ │ │ │ └── page-metric.component.ts │ │ │ │ │ └── page │ │ │ │ │ │ ├── page.component.html │ │ │ │ │ │ ├── page.component.scss │ │ │ │ │ │ ├── page.component.spec.ts │ │ │ │ │ │ └── page.component.ts │ │ │ │ └── models │ │ │ │ │ ├── failing-job-statistic.model.ts │ │ │ │ │ ├── graphite-server.model.ts │ │ │ │ │ ├── location.model.ts │ │ │ │ │ ├── page-csi.model.ts │ │ │ │ │ └── page-metrics.model.ts │ │ │ ├── aspect-configuration │ │ │ │ ├── aspect-configuration.component.html │ │ │ │ ├── aspect-configuration.component.scss │ │ │ │ ├── aspect-configuration.component.spec.ts │ │ │ │ ├── aspect-configuration.component.ts │ │ │ │ ├── aspect-configuration.module.ts │ │ │ │ ├── components │ │ │ │ │ ├── aspect-metrics │ │ │ │ │ │ ├── aspect-metrics.component.html │ │ │ │ │ │ ├── aspect-metrics.component.scss │ │ │ │ │ │ ├── aspect-metrics.component.spec.ts │ │ │ │ │ │ └── aspect-metrics.component.ts │ │ │ │ │ └── edit-aspect-metrics │ │ │ │ │ │ ├── edit-aspect-metrics.component.html │ │ │ │ │ │ ├── edit-aspect-metrics.component.scss │ │ │ │ │ │ ├── edit-aspect-metrics.component.spec.ts │ │ │ │ │ │ └── edit-aspect-metrics.component.ts │ │ │ │ └── services │ │ │ │ │ ├── aspect-configuration.service.spec.ts │ │ │ │ │ └── aspect-configuration.service.ts │ │ │ ├── distribution │ │ │ │ ├── components │ │ │ │ │ ├── util │ │ │ │ │ │ └── chart-label-util.ts │ │ │ │ │ └── violin-chart │ │ │ │ │ │ ├── violin-chart.component.html │ │ │ │ │ │ ├── violin-chart.component.scss │ │ │ │ │ │ ├── violin-chart.component.spec.ts │ │ │ │ │ │ └── violin-chart.component.ts │ │ │ │ ├── distribution.component.html │ │ │ │ ├── distribution.component.scss │ │ │ │ ├── distribution.component.spec.ts │ │ │ │ ├── distribution.component.ts │ │ │ │ ├── distribution.module.ts │ │ │ │ ├── models │ │ │ │ │ ├── distribution-data.model.ts │ │ │ │ │ ├── distribution.model.ts │ │ │ │ │ └── get-violin-chart-command.model.ts │ │ │ │ └── services │ │ │ │ │ ├── violin-chart-math.service.ts │ │ │ │ │ ├── violinchart-data.service.spec.ts │ │ │ │ │ └── violinchart-data.service.ts │ │ │ ├── job-threshold │ │ │ │ ├── components │ │ │ │ │ ├── threshold-group │ │ │ │ │ │ ├── threshold-group.component.html │ │ │ │ │ │ ├── threshold-group.component.scss │ │ │ │ │ │ ├── threshold-group.component.spec.ts │ │ │ │ │ │ └── threshold-group.component.ts │ │ │ │ │ ├── threshold-row │ │ │ │ │ │ ├── threshold-row.component.html │ │ │ │ │ │ ├── threshold-row.component.scss │ │ │ │ │ │ ├── threshold-row.component.spec.ts │ │ │ │ │ │ └── threshold-row.component.ts │ │ │ │ │ └── threshold │ │ │ │ │ │ ├── threshold.component.html │ │ │ │ │ │ ├── threshold.component.scss │ │ │ │ │ │ ├── threshold.component.spec.ts │ │ │ │ │ │ └── threshold.component.ts │ │ │ │ ├── job-threshold.component.html │ │ │ │ ├── job-threshold.component.scss │ │ │ │ ├── job-threshold.component.ts │ │ │ │ ├── job-threshold.module.ts │ │ │ │ ├── models │ │ │ │ │ ├── measurand.model.ts │ │ │ │ │ ├── measured-event.model.ts │ │ │ │ │ ├── tested-page.model.ts │ │ │ │ │ ├── threshold-for-job.model.ts │ │ │ │ │ ├── threshold.model.ts │ │ │ │ │ └── unit.model.ts │ │ │ │ └── services │ │ │ │ │ ├── measurand.service.ts │ │ │ │ │ ├── measured-event.service.ts │ │ │ │ │ ├── threshold-rest.service.ts │ │ │ │ │ └── threshold.service.ts │ │ │ ├── landing │ │ │ │ ├── components │ │ │ │ │ └── continue-setup │ │ │ │ │ │ ├── continue-setup.component.html │ │ │ │ │ │ ├── continue-setup.component.scss │ │ │ │ │ │ ├── continue-setup.component.spec.ts │ │ │ │ │ │ └── continue-setup.component.ts │ │ │ │ ├── landing.component.html │ │ │ │ ├── landing.component.scss │ │ │ │ ├── landing.component.spec.ts │ │ │ │ ├── landing.component.ts │ │ │ │ ├── landing.module.spec.ts │ │ │ │ ├── landing.module.ts │ │ │ │ └── models │ │ │ │ │ ├── application-with-csi.model.ts │ │ │ │ │ └── failing-jobs.model.ts │ │ │ ├── metric-finder │ │ │ │ ├── components │ │ │ │ │ ├── comparable-filmstrips │ │ │ │ │ │ ├── comparable-filmstrips.component.html │ │ │ │ │ │ ├── comparable-filmstrips.component.scss │ │ │ │ │ │ ├── comparable-filmstrips.component.spec.ts │ │ │ │ │ │ └── comparable-filmstrips.component.ts │ │ │ │ │ ├── filmstrip │ │ │ │ │ │ ├── filmstrip.component.html │ │ │ │ │ │ ├── filmstrip.component.scss │ │ │ │ │ │ ├── filmstrip.component.spec.ts │ │ │ │ │ │ └── filmstrip.component.ts │ │ │ │ │ ├── line-chart │ │ │ │ │ │ ├── line-chart.component.html │ │ │ │ │ │ ├── line-chart.component.scss │ │ │ │ │ │ ├── line-chart.component.spec.ts │ │ │ │ │ │ └── line-chart.component.ts │ │ │ │ │ └── metric-selection │ │ │ │ │ │ ├── metric-selection.component.html │ │ │ │ │ │ ├── metric-selection.component.scss │ │ │ │ │ │ ├── metric-selection.component.spec.ts │ │ │ │ │ │ └── metric-selection.component.ts │ │ │ │ ├── metric-finder.component.html │ │ │ │ ├── metric-finder.component.scss │ │ │ │ ├── metric-finder.component.spec.ts │ │ │ │ ├── metric-finder.component.ts │ │ │ │ ├── metric-finder.module.ts │ │ │ │ ├── models │ │ │ │ │ ├── filmstrip-view.model.ts │ │ │ │ │ ├── test-result.model.ts │ │ │ │ │ ├── thumbnail.model.ts │ │ │ │ │ └── wptResult-dto.model.ts │ │ │ │ └── services │ │ │ │ │ ├── filmstrip.service.mock.ts │ │ │ │ │ ├── filmstrip.service.spec.ts │ │ │ │ │ ├── filmstrip.service.ts │ │ │ │ │ ├── metric-finder.service.mock.ts │ │ │ │ │ ├── metric-finder.service.spec.ts │ │ │ │ │ └── metric-finder.service.ts │ │ │ ├── page-comparison │ │ │ │ ├── components │ │ │ │ │ └── page-comparison-row │ │ │ │ │ │ ├── page-comparison-row.component.html │ │ │ │ │ │ └── page-comparison-row.component.ts │ │ │ │ ├── models │ │ │ │ │ ├── job-group-to-page-mapping.model.ts │ │ │ │ │ ├── page-comparison-selection.model.ts │ │ │ │ │ └── page.model.ts │ │ │ │ ├── page-comparison.adapter.ts │ │ │ │ ├── page-comparison.component.html │ │ │ │ ├── page-comparison.component.ts │ │ │ │ ├── page-comparison.module.ts │ │ │ │ └── services │ │ │ │ │ ├── job-group.service.spec.ts │ │ │ │ │ └── job-group.service.ts │ │ │ ├── queue-dashboard │ │ │ │ ├── components │ │ │ │ │ └── location-info-list │ │ │ │ │ │ ├── location-info-list.component.html │ │ │ │ │ │ ├── location-info-list.component.scss │ │ │ │ │ │ ├── location-info-list.component.spec.ts │ │ │ │ │ │ └── location-info-list.component.ts │ │ │ │ ├── models │ │ │ │ │ ├── LocationInfoDTO.ts │ │ │ │ │ └── WptServerDTO.ts │ │ │ │ ├── queue-dashboard.component.html │ │ │ │ ├── queue-dashboard.component.scss │ │ │ │ ├── queue-dashboard.component.spec.ts │ │ │ │ ├── queue-dashboard.component.ts │ │ │ │ ├── queue-dashboard.module.ts │ │ │ │ └── services │ │ │ │ │ └── queue-dashboard.service.ts │ │ │ ├── result-selection │ │ │ │ ├── components │ │ │ │ │ ├── application │ │ │ │ │ │ ├── application.component.html │ │ │ │ │ │ ├── application.component.scss │ │ │ │ │ │ ├── application.component.spec.ts │ │ │ │ │ │ └── application.component.ts │ │ │ │ │ ├── measurands │ │ │ │ │ │ ├── measurand-select │ │ │ │ │ │ │ ├── measurand-select.component.html │ │ │ │ │ │ │ ├── measurand-select.component.scss │ │ │ │ │ │ │ ├── measurand-select.component.spec.ts │ │ │ │ │ │ │ └── measurand-select.component.ts │ │ │ │ │ │ ├── measurands.component.html │ │ │ │ │ │ ├── measurands.component.scss │ │ │ │ │ │ ├── measurands.component.spec.ts │ │ │ │ │ │ └── measurands.component.ts │ │ │ │ │ ├── page-location-connectivity │ │ │ │ │ │ ├── page-location-connectivity.component.html │ │ │ │ │ │ ├── page-location-connectivity.component.scss │ │ │ │ │ │ ├── page-location-connectivity.component.spec.ts │ │ │ │ │ │ ├── page-location-connectivity.component.ts │ │ │ │ │ │ └── selection-data │ │ │ │ │ │ │ ├── selection-data.component.html │ │ │ │ │ │ │ ├── selection-data.component.scss │ │ │ │ │ │ │ ├── selection-data.component.spec.ts │ │ │ │ │ │ │ └── selection-data.component.ts │ │ │ │ │ ├── reset │ │ │ │ │ │ ├── reset.component.html │ │ │ │ │ │ ├── reset.component.scss │ │ │ │ │ │ ├── reset.component.spec.ts │ │ │ │ │ │ └── reset.component.ts │ │ │ │ │ ├── submit │ │ │ │ │ │ ├── submit.component.html │ │ │ │ │ │ ├── submit.component.scss │ │ │ │ │ │ ├── submit.component.spec.ts │ │ │ │ │ │ └── submit.component.ts │ │ │ │ │ └── time-frame │ │ │ │ │ │ ├── time-frame-in-seconds.enum.ts │ │ │ │ │ │ ├── time-frame.component.html │ │ │ │ │ │ ├── time-frame.component.scss │ │ │ │ │ │ ├── time-frame.component.spec.ts │ │ │ │ │ │ └── time-frame.component.ts │ │ │ │ ├── models │ │ │ │ │ ├── chart-switch-menu-entry.model.ts │ │ │ │ │ ├── remaing-result-selection.model.ts │ │ │ │ │ └── result-selection-command.model.ts │ │ │ │ ├── result-selection.component.html │ │ │ │ ├── result-selection.component.scss │ │ │ │ ├── result-selection.component.spec.ts │ │ │ │ ├── result-selection.component.ts │ │ │ │ ├── result-selection.module.ts │ │ │ │ └── services │ │ │ │ │ ├── result-selection.service.spec.ts │ │ │ │ │ ├── result-selection.service.ts │ │ │ │ │ ├── result-selection.store.spec.ts │ │ │ │ │ └── result-selection.store.ts │ │ │ ├── shared │ │ │ │ ├── components │ │ │ │ │ ├── chart-switch-menu │ │ │ │ │ │ ├── chart-switch-menu.component.html │ │ │ │ │ │ ├── chart-switch-menu.component.scss │ │ │ │ │ │ ├── chart-switch-menu.component.spec.ts │ │ │ │ │ │ └── chart-switch-menu.component.ts │ │ │ │ │ ├── csi-value │ │ │ │ │ │ ├── csi-value-base.component.html │ │ │ │ │ │ ├── csi-value-base.component.scss │ │ │ │ │ │ ├── csi-value-base.component.spec.ts │ │ │ │ │ │ ├── csi-value-base.component.ts │ │ │ │ │ │ ├── csi-value-big │ │ │ │ │ │ │ ├── csi-value-big.component.html │ │ │ │ │ │ │ ├── csi-value-big.component.scss │ │ │ │ │ │ │ ├── csi-value-big.component.spec.ts │ │ │ │ │ │ │ └── csi-value-big.component.ts │ │ │ │ │ │ ├── csi-value-medium │ │ │ │ │ │ │ ├── csi-value-medium.component.html │ │ │ │ │ │ │ ├── csi-value-medium.component.scss │ │ │ │ │ │ │ ├── csi-value-medium.component.spec.ts │ │ │ │ │ │ │ └── csi-value-medium.component.ts │ │ │ │ │ │ ├── csi-value-small │ │ │ │ │ │ │ ├── csi-value-small.component.html │ │ │ │ │ │ │ ├── csi-value-small.component.scss │ │ │ │ │ │ │ ├── csi-value-small.component.spec.ts │ │ │ │ │ │ │ └── csi-value-small.component.ts │ │ │ │ │ │ └── csi-value-svg.renderer.ts │ │ │ │ │ ├── empty-state │ │ │ │ │ │ ├── empty-state.component.html │ │ │ │ │ │ ├── empty-state.component.scss │ │ │ │ │ │ ├── empty-state.component.spec.ts │ │ │ │ │ │ └── empty-state.component.ts │ │ │ │ │ └── spinner │ │ │ │ │ │ ├── spinner.component.html │ │ │ │ │ │ ├── spinner.component.scss │ │ │ │ │ │ ├── spinner.component.spec.ts │ │ │ │ │ │ └── spinner.component.ts │ │ │ │ ├── services │ │ │ │ │ ├── measurand-color.service.ts │ │ │ │ │ └── spinner.service.ts │ │ │ │ ├── shared.module.spec.ts │ │ │ │ └── shared.module.ts │ │ │ └── time-series │ │ │ │ ├── components │ │ │ │ └── time-series-chart │ │ │ │ │ ├── time-series-chart.component.html │ │ │ │ │ ├── time-series-chart.component.scss │ │ │ │ │ ├── time-series-chart.component.spec.ts │ │ │ │ │ └── time-series-chart.component.ts │ │ │ │ ├── models │ │ │ │ ├── context-menu-position.model.ts │ │ │ │ ├── event-result-data.model.ts │ │ │ │ ├── event-result-point.model.ts │ │ │ │ ├── event-result-series.model.ts │ │ │ │ ├── get-line-chart-command.model.ts │ │ │ │ ├── points-selection.model.ts │ │ │ │ ├── summary-label.model.ts │ │ │ │ ├── time-series-point.model.ts │ │ │ │ ├── time-series.model.ts │ │ │ │ └── wpt-info.model.ts │ │ │ │ ├── services │ │ │ │ ├── chart-services │ │ │ │ │ ├── line-chart-draw.service.ts │ │ │ │ │ ├── line-chart-event.service.ts │ │ │ │ │ ├── line-chart-legend.service.ts │ │ │ │ │ └── line-chart-scale.service.ts │ │ │ │ ├── line-chart-data.service.ts │ │ │ │ ├── line-chart.service.ts │ │ │ │ └── url-builder.service.ts │ │ │ │ ├── time-series.component.html │ │ │ │ ├── time-series.component.scss │ │ │ │ ├── time-series.component.ts │ │ │ │ └── time-series.module.ts │ │ ├── not-found.component.ts │ │ ├── services │ │ │ ├── application.service.spec.ts │ │ │ ├── application.service.ts │ │ │ ├── grails-bridge.service.ts │ │ │ ├── osm-lang.service.spec.ts │ │ │ ├── osm-lang.service.ts │ │ │ ├── performance-aspect.service.spec.ts │ │ │ └── performance-aspect.service.ts │ │ ├── testing │ │ │ ├── ngx-translate-mocks.ts │ │ │ └── shared-mocks.module.ts │ │ └── utils │ │ │ ├── calculation.util.ts │ │ │ ├── csi-utils.ts │ │ │ ├── date.util.spec.ts │ │ │ └── date.util.ts │ ├── assets │ │ ├── .gitkeep │ │ ├── OpenSpeedMonitor_dark.svg │ │ ├── undraw_fast_loading.svg │ │ └── undraw_setup_wizard.svg │ ├── browserslist │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── index.html │ ├── karma.conf.js │ ├── main.ts │ ├── polyfills.ts │ ├── styles.scss │ ├── styles │ │ ├── cards.scss │ │ ├── clickable-list.scss │ │ ├── colors.scss │ │ ├── fonts.scss │ │ ├── layout.scss │ │ ├── modals.scss │ │ └── variables.scss │ ├── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ └── tslint.json ├── tsconfig.json └── tslint.json ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── grails-app ├── assets │ ├── images │ │ ├── OpenSpeedMonitor.svg │ │ ├── OpenSpeedMonitor_Icon.png │ │ ├── OpenSpeedMonitor_dark.svg │ │ ├── OpenSpeedMonitor_original.svg │ │ ├── OpenSpeedMonitor_small.svg │ │ ├── OpenSpeedMonitor_white.svg │ │ ├── WPT.png │ │ ├── api.png │ │ ├── csi.png │ │ ├── exampleScript.png │ │ ├── favicon.ico │ │ ├── flags.png │ │ ├── glyphicons-halflings-white.png │ │ ├── glyphicons-halflings.png │ │ ├── iteratec-logo.png │ │ ├── jobGroupSelection.png │ │ ├── jobs.png │ │ ├── leftnav_btm.png │ │ ├── leftnav_midstretch.png │ │ ├── leftnav_top.png │ │ ├── loading_indicator.gif │ │ ├── menu-separator.png │ │ ├── results.png │ │ ├── skin │ │ │ ├── database_add.png │ │ │ ├── database_delete.png │ │ │ ├── database_edit.png │ │ │ ├── database_save.png │ │ │ ├── database_table.png │ │ │ ├── exclamation.png │ │ │ ├── house.png │ │ │ ├── information.png │ │ │ ├── shadow.jpg │ │ │ ├── sorted_asc.gif │ │ │ └── sorted_desc.gif │ │ └── spinner.gif │ ├── javascripts │ │ ├── _resultSelection │ │ │ ├── _connectedSelects.js │ │ │ ├── _selectWithSelectAllCheckBox.js │ │ │ ├── _timeRangePicker.js │ │ │ ├── resultSelection.js │ │ │ ├── selectBarchartMeasurings.js │ │ │ ├── selectIntervalTimeframeCard.js │ │ │ ├── selectJobGroupCard.js │ │ │ ├── selectPageLocationConnectivityCard.js │ │ │ └── selectUserTimingsCard.js │ │ ├── aggregation │ │ │ ├── aggregation.js │ │ │ ├── aggregationChart.js │ │ │ ├── aggregationChartData.js │ │ │ ├── aggregationGuiHandling.js │ │ │ └── aggregationHistoryStateHandling.js │ │ ├── application.js │ │ ├── batchactivity │ │ │ └── batchActivityList.js │ │ ├── chartComponents │ │ │ ├── chartBarScore.js │ │ │ ├── chartBars.js │ │ │ ├── chartHeader.js │ │ │ ├── chartLegend.js │ │ │ ├── chartMultiLegend.js │ │ │ ├── chartSideLabels.js │ │ │ ├── common.js │ │ │ └── utility.js │ │ ├── chartSwitch.js │ │ ├── charts │ │ │ ├── chart-adjustment.js │ │ │ ├── chart-export.js │ │ │ ├── chartContextUtilities.js │ │ │ └── rgbcolor.js │ │ ├── codemirror │ │ │ ├── codemirror-usage.js │ │ │ ├── codemirrorManifest.js │ │ │ ├── hint │ │ │ │ └── pts-hint.js │ │ │ └── mode │ │ │ │ └── pts.js │ │ ├── csi │ │ │ ├── configurationPost.js │ │ │ ├── defaultMappingCsvValidator.js │ │ │ ├── deleteCsiConfigValidation.js │ │ │ └── pageMappingDeletion.js │ │ ├── csiBenchmark │ │ │ ├── csiBenchmark.js │ │ │ └── csiBenchmarkChart.js │ │ ├── csidashboard │ │ │ └── showAll.js │ │ ├── d3 │ │ │ ├── barChart.js │ │ │ ├── chartColorProvider.js │ │ │ ├── chartLabelUtil.js │ │ │ ├── clocks.js │ │ │ ├── forceDirectedGraph.js │ │ │ ├── matrixView.js │ │ │ ├── multiLineChart.js │ │ │ ├── scheduleChart.js │ │ │ ├── trafficLightDataProvider.js │ │ │ ├── treeMapDesigner.js │ │ │ └── treemap.js │ │ ├── distributionChart │ │ │ ├── distributionChart.js │ │ │ └── distributionChartUrlHandling.js │ │ ├── eventresult │ │ │ ├── eventResult.js │ │ │ └── listResult.js │ │ ├── eventresultdashboard │ │ │ ├── eventResultDashboard.js │ │ │ └── showAll.js │ │ ├── infrastructureSetup │ │ │ └── infrastructureSetupWizard.js │ │ ├── iteratecChartRickshaw.js │ │ ├── job │ │ │ ├── edit.js │ │ │ ├── jobList.js │ │ │ ├── jobListFilter.js │ │ │ └── list.js │ │ ├── jobResult │ │ │ └── failedJobResultList.js │ │ ├── kickstart │ │ │ └── checkboxes.js │ │ ├── location │ │ │ └── locationListFilter.js │ │ ├── measurementSetup │ │ │ ├── _createJob.js │ │ │ ├── _createJobGroup.js │ │ │ ├── _createScript.js │ │ │ ├── _selectLocationAndConnectivity.js │ │ │ ├── _wizard.js │ │ │ └── measurementSetupWizard.js │ │ ├── pageComparison │ │ │ ├── pageComparison.js │ │ │ ├── pageComparisonChart.js │ │ │ ├── pageComparisonChartData.js │ │ │ ├── pageComparisonGuiHandling.js │ │ │ └── pageComparisonHistoryStateHandling.js │ │ ├── pngDownloader.js │ │ ├── postload │ │ │ └── application-postload.js │ │ ├── prettycron │ │ │ ├── cron-expressions.js │ │ │ └── prettycronManifest.js │ │ ├── responsiveTable │ │ │ └── responsiveTable.js │ │ ├── rickshaw │ │ │ ├── SimpleGraphBuilder.js │ │ │ ├── html2canvas.js │ │ │ ├── html2canvas.svg.js │ │ │ ├── rickshaw.min.js │ │ │ ├── rickshawChartCreation.js │ │ │ └── rickshaw_custom.js │ │ ├── script │ │ │ ├── list.js │ │ │ └── versionControl.js │ │ ├── spinner.js │ │ ├── timeago │ │ │ ├── future-only-timeago.js │ │ │ ├── futureOnlyTimeago.js │ │ │ ├── jquery.timeago.de.js │ │ │ ├── jquery.timeago.js │ │ │ └── timeagoDe.js │ │ └── urlHandling │ │ │ └── urlHelper.js │ └── stylesheets │ │ ├── README.md │ │ ├── _resultSelection │ │ └── selectBarchartMeasurings.css │ │ ├── aggregation │ │ └── show.less │ │ ├── application.less │ │ ├── bootstrap-chosen-custom.less │ │ ├── cards.less │ │ ├── codemirror │ │ ├── codemirrorManifest.css │ │ └── warnings.css │ │ ├── csiBenchmark │ │ └── show.less │ │ ├── csiDashboard │ │ └── csiDashboard.less │ │ ├── d3Charts │ │ ├── barChart.less │ │ ├── barChartHorizontal.less │ │ ├── clocks.less │ │ ├── d3chart.less │ │ ├── distributionChart.less │ │ ├── forceDirectedGraph.less │ │ ├── scheduleChart.less │ │ └── treemap.less │ │ ├── dimple │ │ └── barchart.css │ │ ├── errors.css │ │ ├── flags.less │ │ ├── fontawesome.less │ │ ├── infrastructureSetup │ │ └── infrastructureSetup.less │ │ ├── job │ │ ├── edit.less │ │ └── list.less │ │ ├── kickstart │ │ └── docs.css │ │ ├── landing │ │ └── index.less │ │ ├── openspeedmonitor.less │ │ ├── queueStatus │ │ └── list.css │ │ ├── rickshaw │ │ └── rickshaw_custom.css │ │ ├── script │ │ ├── scriptManifest.css │ │ └── versionControl.css │ │ ├── setupWizard │ │ └── setupWizard.less │ │ ├── sidebar.less │ │ ├── tabularResultPresentation │ │ └── listResults.css │ │ ├── tagit.css │ │ └── variables-corporate.less ├── conf │ ├── OpenSpeedMonitor-config.yml.sample │ ├── QuartzConfig.groovy │ ├── application.yml │ ├── logback.groovy │ └── spring │ │ └── resources.groovy ├── controllers │ └── de │ │ └── iteratec │ │ └── osm │ │ ├── ApiDocController.groovy │ │ ├── LandingController.groovy │ │ ├── OsmConfigurationController.groovy │ │ ├── UrlMappings.groovy │ │ ├── api │ │ ├── ApiKeyController.groovy │ │ ├── CsiApiController.groovy │ │ ├── DetailDataApiController.groovy │ │ ├── GeneralMeasurementApiController.groovy │ │ ├── JobApiController.groovy │ │ ├── RawResultsApiController.groovy │ │ └── RestApiInterceptor.groovy │ │ ├── batch │ │ └── BatchActivityController.groovy │ │ ├── csi │ │ ├── CsTargetGraphController.groovy │ │ ├── CsTargetValueController.groovy │ │ ├── CsiBenchmarkController.groovy │ │ ├── CsiConfigIOController.groovy │ │ ├── CsiConfigurationController.groovy │ │ ├── CsiDashboardController.groovy │ │ ├── CsiSystemController.groovy │ │ └── PageController.groovy │ │ ├── measurement │ │ ├── environment │ │ │ ├── BrowserAliasController.groovy │ │ │ ├── BrowserController.groovy │ │ │ ├── InfrastructureSetupController.groovy │ │ │ ├── JobScheduleController.groovy │ │ │ ├── LocationController.groovy │ │ │ ├── QueueDashboardController.groovy │ │ │ └── WebPageTestServerController.groovy │ │ ├── schedule │ │ │ ├── ConnectivityProfileController.groovy │ │ │ ├── JobController.groovy │ │ │ └── JobGroupController.groovy │ │ ├── script │ │ │ └── ScriptController.groovy │ │ └── setup │ │ │ └── MeasurementSetupController.groovy │ │ ├── report │ │ ├── chart │ │ │ ├── CsiAggregationController.groovy │ │ │ └── EventController.groovy │ │ └── external │ │ │ ├── GraphiteEventSourcePathController.groovy │ │ │ ├── GraphitePathCsiDataController.groovy │ │ │ ├── GraphitePathRawDataController.groovy │ │ │ └── GraphiteServerController.groovy │ │ ├── result │ │ ├── AggregationController.groovy │ │ ├── AggregationLegacyController.groovy │ │ ├── ApplicationDashboardController.groovy │ │ ├── AspectConfigurationController.groovy │ │ ├── DetailAnalysisController.groovy │ │ ├── DistributionChartController.groovy │ │ ├── EventResultDashboardController.groovy │ │ ├── HighchartPointDetailsController.groovy │ │ ├── JobResultController.groovy │ │ ├── MeasuredEventController.groovy │ │ ├── MetricFinderController.groovy │ │ ├── PageComparisonController.groovy │ │ ├── ResultSelectionController.groovy │ │ ├── TabularResultPresentationController.groovy │ │ └── ThresholdController.groovy │ │ ├── security │ │ ├── RegisterController.groovy │ │ ├── RegistrationCodeController.groovy │ │ ├── RequestmapController.groovy │ │ ├── SecurityInfoController.groovy │ │ └── UserController.groovy │ │ └── util │ │ ├── CronExpressionController.groovy │ │ └── ExceptionHandlerController.groovy ├── domain │ └── de │ │ └── iteratec │ │ └── osm │ │ ├── OsmConfiguration.groovy │ │ ├── api │ │ └── ApiKey.groovy │ │ ├── batch │ │ └── BatchActivity.groovy │ │ ├── csi │ │ ├── BrowserConnectivityWeight.groovy │ │ ├── CsTargetGraph.groovy │ │ ├── CsTargetValue.groovy │ │ ├── CsiConfiguration.groovy │ │ ├── CsiDay.groovy │ │ ├── CsiSystem.groovy │ │ ├── DefaultTimeToCsMapping.groovy │ │ ├── HourOfDay.groovy │ │ ├── JobGroupWeight.groovy │ │ ├── Page.groovy │ │ ├── PageWeight.groovy │ │ └── TimeToCsMapping.groovy │ │ ├── measurement │ │ ├── environment │ │ │ ├── Browser.groovy │ │ │ ├── BrowserAlias.groovy │ │ │ ├── Location.groovy │ │ │ └── WebPageTestServer.groovy │ │ ├── schedule │ │ │ ├── ConnectivityProfile.groovy │ │ │ ├── Job.groovy │ │ │ ├── JobGroup.groovy │ │ │ └── JobStatistic.groovy │ │ └── script │ │ │ ├── ArchivedScript.groovy │ │ │ └── Script.groovy │ │ ├── report │ │ ├── UserspecificCsiDashboard.groovy │ │ ├── UserspecificDashboardBase.groovy │ │ ├── UserspecificEventResultDashboard.groovy │ │ ├── chart │ │ │ ├── CsiAggregation.groovy │ │ │ ├── CsiAggregationInterval.groovy │ │ │ ├── CsiAggregationUpdateEvent.groovy │ │ │ └── Event.groovy │ │ └── external │ │ │ ├── GraphiteEventSourcePath.groovy │ │ │ ├── GraphitePathCsiData.groovy │ │ │ ├── GraphitePathRawData.groovy │ │ │ └── GraphiteServer.groovy │ │ ├── result │ │ ├── EventResult.groovy │ │ ├── JobResult.groovy │ │ ├── MeasuredEvent.groovy │ │ ├── PerformanceAspect.groovy │ │ ├── ResultSelectionInformation.groovy │ │ ├── Threshold.groovy │ │ ├── UserTiming.groovy │ │ └── UserTimingSelectionInformation.groovy │ │ ├── security │ │ ├── Role.groovy │ │ ├── User.groovy │ │ └── UserRole.groovy │ │ └── system │ │ ├── LocationHealthCheck.groovy │ │ └── MissingJobResultCheck.groovy ├── i18n │ ├── messages.properties │ └── messages_de.properties ├── init │ ├── BootStrap.groovy │ └── de │ │ └── iteratec │ │ └── osm │ │ ├── Application.groovy │ │ └── FrontendWatcher.groovy ├── jobs │ └── de │ │ └── iteratec │ │ └── osm │ │ ├── measurement │ │ └── schedule │ │ │ ├── CloseRunningAndPendingJobResultsJob.groovy │ │ │ └── quartzjobs │ │ │ └── JobProcessingQuartzHandlerJob.groovy │ │ ├── persistence │ │ ├── DbCleanupOldBatchActivitiesJob.groovy │ │ ├── DbCleanupOldCsiAggregationsWithDependenciesJob.groovy │ │ └── DbCleanupOldJobResultsWithDependenciesJob.groovy │ │ ├── report │ │ ├── chart │ │ │ └── CsiAggregationUpdateEventCleanupJob.groovy │ │ └── external │ │ │ ├── DailyReportsJob.groovy │ │ │ ├── GraphiteEventCollectorJob.groovy │ │ │ ├── GraphiteReportJob.groovy │ │ │ ├── HourlyReportsJob.groovy │ │ │ ├── JobHealthReportJob.groovy │ │ │ └── WeeklyReportsJob.groovy │ │ ├── result │ │ └── ResultSelectionInformationCreationJob.groovy │ │ └── system │ │ ├── LocationHealthCheckCleanupJob.groovy │ │ ├── LocationHealthCheckJob.groovy │ │ └── MissingJobResultCheckJob.groovy ├── migrations │ ├── .gitignore │ ├── 2015-11-18-DATA-multiply-csi-values-by-100.groovy │ ├── 2015-11-18-DATA-set-initial-csi-transformation.groovy │ ├── 2015-11-18-SCHEME-initial-liquibase.groovy │ ├── 2015-11-26-SCHEME-optimizing-indices.groovy │ ├── 2015-12-09-SCHEME-csi-configuration.groovy │ ├── 2015-12-15-SCHEME-measured-value-and-connectivity-profile.groovy │ ├── 2015-12-16-DATA-delete-invalid-default-csi-mappings.groovy │ ├── 2015-12-22-DATA-delete-measured-value-update-events.groovy │ ├── 2015-12-23-DATA-convert-hoursOfDay-to-CsiDay.groovy │ ├── 2015-12-23-SCHEME-CsiDay-class-with-hoursOfDay.groovy │ ├── 2015-12-23-SCHEME-added-csiConfiguration-to-jobGroup.groovy │ ├── 2015-12-23-SCHEME-replaced-hourOfDays-with-CsiDay-in-CsiConfiguration.groovy │ ├── 2016-01-04-DATA-create-initial-browser-connectivity-weights.groovy │ ├── 2016-02-22-DATA-v340.groovy │ ├── 2016-02-22-SCHEME-v340.groovy │ ├── 2016-02-24-DATA-v341.groovy │ ├── 2016-02-24-SCHEME-v341.groovy │ ├── 2016-03-02-SCHEME-v346.groovy │ ├── 2016-03-04-SCHEME-v347.groovy │ ├── 2016-03-30-SCHEME-v348.groovy │ ├── 2016-06-17-SCHEME-v349.groovy │ ├── 2016-08-12-DATA-v350.groovy │ ├── 2016-08-12-SCHEME-v350.groovy │ ├── 2016-09-08-DATA-v352.groovy │ ├── 2016-09-08-SCHEME-v352.groovy │ ├── 2016-09-30-SCHEME-v354.groovy │ ├── 2016-10-26-DATA-v355.groovy │ ├── 2016-10-26-SCHEME-v355.groovy │ ├── 2016-12-12-SCHEME-v400.groovy │ ├── 2016-12-20-SCHEME-v410.groovy │ ├── 2017-01-30-SCHEME-v411.groovy │ ├── 2017-02-23-SCHEME-v412.groovy │ ├── 2017-03-21-DATA-v413.groovy │ ├── 2017-03-21-SCHEME-v413.groovy │ ├── 2017-05-03-DATA-v414.groovy │ ├── 2017-05-03-SCHEME-v414.groovy │ ├── 2017-05-12-SCHEME-v414.groovy │ ├── 2017-05-19-DATA-v414.groovy │ ├── 2017-05-19-SCHEME-v414.groovy │ ├── 2017-06-13-DATA-v420_beta.groovy │ ├── 2017-06-16-SCHEME-v420_beta_2.groovy │ ├── 2017-06-21-DATA-v420_beta_2.groovy │ ├── 2017-06-21-SCHEME-v420_beta_2.groovy │ ├── 2017-06-22-SCHEME-v420_beta_2.groovy │ ├── 2017-07-04-DATA-v420_beta_2.groovy │ ├── 2017-07-04-SCHEME-v420_beta_2.groovy │ ├── 2017-07-05-SCHEME-v420_beta_2.groovy │ ├── 2017-07-10-SCHEME-v420_beta_2.groovy │ ├── 2017-07-12-SCHEME-v420_beta_2.groovy │ ├── 2017-07-18-DATA-v420_beta_2.groovy │ ├── 2017-07-19-SCHEME-v420_beta_2.groovy │ ├── 2017-07-25-SCHEME-v420_beta_2.groovy │ ├── 2017-07-27-SCHEME-v420_beta_2.groovy │ ├── 2017-08-31-DATA-v430.groovy │ ├── 2017-09-06-SCHEME-v431.groovy │ ├── 2017-09-21-SCHEME-v432.groovy │ ├── 2017-09-26-SCHEME-v433.groovy │ ├── 2017-10-10-v440-fixGraphitePaths.groovy │ ├── 2017-12-19-v440-addGlobalUAConfigColumn.groovy │ ├── 2017-12-19-v440-improveTimeSeriesPerformance.groovy │ ├── 2018-01-09-v440-addUseGlobalUASuffixBool.groovy │ ├── 2018-01-17-v440-addThreshold.groovy │ ├── 2018-02-20-v450-dropMainUrl.groovy │ ├── 2018-06-20-v460-removeScriptPageRelations.groovy │ ├── 2018-09-27-SCHEME-v510-remove-csi-by-rank.groovy │ ├── 2018-10-01-v500-job-label-optional.groovy │ ├── 2018-10-10-v500-locationHealthCheck-add-index.groovy │ ├── 2018-10-11-v500-job-result-status.groovy │ ├── 2018-11-06-v500-job-result-expected-results.groovy │ ├── 2018-11-15-v500-hero-element-times.groovy │ ├── 2018-11-16-v500-add-new-measurands.groovy │ ├── 2018-11-19-v500-add-missing-job-result-check.groovy │ ├── 2018-11-19-v500-job-group-graphite-servers.groovy │ ├── 2018-11-30-v500-remove-waterfall-url.groovy │ ├── 2018-12-12-v500-nullable-job-result-label.groovy │ ├── 2019-03-13-v511-add-performance-aspect.groovy │ ├── 2019-04-30-v512-browser-in-perf-aspect.groovy │ ├── 2019-05-06-v512-add-os-and-device-type.groovy │ ├── 2019-05-20-migrate-otto-locations.groovy │ ├── 2019-06-19-add-user-timing-idx.groovy │ ├── 2019-08-05-rename-interactive-fields.groovy │ ├── 2019-09-23-v530-add-first-paint-measurand.groovy │ └── changelog.groovy ├── services │ └── de │ │ └── iteratec │ │ └── osm │ │ ├── ApiDocService.groovy │ │ ├── ConfigService.groovy │ │ ├── InMemoryConfigService.groovy │ │ ├── OsmConfigCacheService.groovy │ │ ├── OsmStateService.groovy │ │ ├── api │ │ ├── CsiByEventResultsService.groovy │ │ └── JobLinkService.groovy │ │ ├── barchart │ │ └── BarchartAggregationService.groovy │ │ ├── batch │ │ └── BatchActivityService.groovy │ │ ├── chartUtilities │ │ └── FilteringAndSortingDataService.groovy │ │ ├── csi │ │ ├── CachingContainerService.groovy │ │ ├── CsTargetGraphDaoService.groovy │ │ ├── CsiAggregationUpdateEventCleanupService.groovy │ │ ├── CsiAggregationUpdateService.groovy │ │ ├── CsiSystemCsiAggregationService.groovy │ │ ├── CustomerSatisfactionHighChartService.groovy │ │ ├── CustomerSatisfactionWeightService.groovy │ │ ├── EventCsiAggregationService.groovy │ │ ├── JobGroupCsiAggregationService.groovy │ │ ├── MeanCalcService.groovy │ │ ├── PageCsiAggregationService.groovy │ │ ├── transformation │ │ │ ├── DefaultTimeToCsMappingService.groovy │ │ │ └── TimeToCsMappingService.groovy │ │ └── weighting │ │ │ └── WeightingService.groovy │ │ ├── integrations │ │ └── CiPipeService.groovy │ │ ├── linechart │ │ └── LineChartTimeSeriesService.groovy │ │ ├── measurement │ │ ├── environment │ │ │ ├── BrowserService.groovy │ │ │ ├── QueueAndJobStatusService.groovy │ │ │ ├── WptServerService.groovy │ │ │ └── wptserver │ │ │ │ ├── DetailAnalysisPersisterService.groovy │ │ │ │ ├── EventResultPersisterService.groovy │ │ │ │ ├── HttpRequestService.groovy │ │ │ │ ├── JobResultPersisterService.groovy │ │ │ │ ├── LocationPersisterService.groovy │ │ │ │ └── WptInstructionService.groovy │ │ ├── schedule │ │ │ ├── ConnectivityProfileDaoService.groovy │ │ │ ├── ConnectivityProfileService.groovy │ │ │ ├── JobDaoService.groovy │ │ │ ├── JobGroupService.groovy │ │ │ ├── JobRunService.groovy │ │ │ ├── JobSchedulingService.groovy │ │ │ ├── JobService.groovy │ │ │ └── JobStatisticService.groovy │ │ └── script │ │ │ └── ScriptService.groovy │ │ ├── p13n │ │ └── CustomDashboardService.groovy │ │ ├── persistence │ │ └── DbCleanupService.groovy │ │ ├── report │ │ ├── UserspecificDashboardService.groovy │ │ ├── chart │ │ │ ├── CsiAggregationDaoService.groovy │ │ │ ├── CsiAggregationUpdateEventDaoService.groovy │ │ │ ├── CsiAggregationUtilService.groovy │ │ │ ├── EventDaoService.groovy │ │ │ ├── EventService.groovy │ │ │ └── OsmChartProcessingService.groovy │ │ └── external │ │ │ ├── GraphiteEventService.groovy │ │ │ ├── GraphiteReportService.groovy │ │ │ ├── HealthReportService.groovy │ │ │ ├── JobHealthReportService.groovy │ │ │ └── MetricReportingService.groovy │ │ ├── result │ │ ├── ApplicationDashboardService.groovy │ │ ├── CsiValueService.groovy │ │ ├── EventResultDashboardService.groovy │ │ ├── PageService.groovy │ │ ├── PaginationService.groovy │ │ ├── ResultSelectionInformationService.groovy │ │ ├── ResultSelectionService.groovy │ │ ├── ThresholdService.groovy │ │ └── dao │ │ │ └── EventResultDaoService.groovy │ │ ├── system │ │ ├── LocationHealthCheckDaoService.groovy │ │ ├── LocationHealthCheckService.groovy │ │ └── MissingJobResultCheckService.groovy │ │ ├── util │ │ ├── CsvExportService.groovy │ │ ├── I18nService.groovy │ │ ├── OsmCookieService.groovy │ │ └── PerformanceLoggingService.groovy │ │ └── violinchart │ │ └── ViolinChartDistributionService.groovy ├── taglib │ ├── de │ │ └── iteratec │ │ │ └── osm │ │ │ ├── d3 │ │ │ └── D3ChartTagLib.groovy │ │ │ └── report │ │ │ ├── chart │ │ │ └── OsmChartTagLib.groovy │ │ │ └── ui │ │ │ ├── I18NReleaseNotes.groovy │ │ │ └── OptGroupedSelectTagLib.groovy │ └── kickstart │ │ └── BootstrapTagLib.groovy └── views │ ├── _common │ ├── _jsGlobals.gsp │ ├── _postloadInitializedJS.gsp │ ├── buttons │ │ ├── _editSymbolLink.gsp │ │ └── _showSymbolLink.gsp │ └── modals │ │ ├── _chartContextMenuErrorDialog.gsp │ │ ├── _chooseCsiMapping.gsp │ │ ├── _createJobGroupModal.gsp │ │ ├── _createUserspecifiedDashboard.gsp │ │ ├── _deleteDialog.gsp │ │ ├── _deleteDialogCsiPageMapping.gsp │ │ ├── _deleteSymbolLink.gsp │ │ ├── _deleteTextLink.gsp │ │ ├── _downloadAsPngDialog.gsp │ │ ├── _p13nByCookies.gsp │ │ ├── _registerDialog.gsp │ │ ├── _registerTextLink.gsp │ │ └── csi │ │ └── _updateCsiConfiguration.gsp │ ├── _errors │ ├── 403.gsp │ ├── 404.gsp │ ├── 503.gsp │ └── error.gsp │ ├── _fields │ ├── _labelTemplate.gsp │ ├── boolean │ │ └── _wrapper.gsp │ ├── date │ │ └── _wrapper.gsp │ ├── enum │ │ └── _wrapper.gsp │ ├── manyToOne │ │ └── _wrapper.gsp │ ├── number │ │ └── _wrapper.gsp │ ├── oneToMany │ │ ├── _bidirectional.gsp │ │ ├── _unidirectional.gsp │ │ └── _wrapper.gsp │ ├── oneToOne │ │ └── _wrapper.gsp │ └── string │ │ └── _wrapper.gsp │ ├── _menu │ ├── _admin.gsp │ ├── _gotoPage.gsp │ ├── _info.gsp │ ├── _language.gsp │ ├── _menubar.gsp │ ├── _navbar.gsp │ ├── _submenubar.gsp │ ├── _submenubarDeleteButton.gsp │ ├── _submenubarNormalButtons.gsp │ ├── _submenubarWithoutDelete.gsp │ └── _user.gsp │ ├── _resultSelection │ ├── _firstViewCard.gsp │ ├── _hiddenWarnings.gsp │ ├── _repeatedViewCard.gsp │ ├── _selectBarchartMeasurings.gsp │ ├── _selectDistributionChartMeasurings.gsp │ ├── _selectIntervalTimeframeCard.gsp │ ├── _selectJobGroupCard.gsp │ ├── _selectMeasuredVariables.gsp │ ├── _selectMeasurings.gsp │ ├── _selectMeasuringsAndTimeFrame.gsp │ ├── _selectPageContent.gsp │ ├── _selectPageLocationConnectivityCard.gsp │ ├── _timeRangePicker.gsp │ └── _trimValuesCard.gsp │ ├── aggregationLegacy │ ├── _adjustBarchartModal.gsp │ ├── _barChart.gsp │ └── show.gsp │ ├── angularFrontend.gsp │ ├── apiKey │ ├── _apiKeyTable.gsp │ └── index.gsp │ ├── batchActivity │ ├── _batchActivityRow.gsp │ ├── _batchActivityTable.gsp │ ├── _form.gsp │ ├── list.gsp │ └── show.gsp │ ├── browser │ ├── _browserTable.gsp │ └── index.gsp │ ├── browserAlias │ ├── _browserAliasTable.gsp │ └── index.gsp │ ├── chart │ ├── _chartSwitchButtons.gsp │ └── _csi-mappings.gsp │ ├── connectivityProfile │ ├── _form.gsp │ ├── create.gsp │ ├── edit.gsp │ └── list.gsp │ ├── csTargetGraph │ ├── _csTargetGraphTable.gsp │ └── index.gsp │ ├── csTargetValue │ ├── _csTargetValueTable.gsp │ └── index.gsp │ ├── csiBenchmark │ ├── _adjustBarchartModal.gsp │ ├── _barChart.gsp │ └── show.gsp │ ├── csiConfiguration │ ├── _confDetails.gsp │ └── configurations.gsp │ ├── csiDashboard │ └── showAll.gsp │ ├── csiSystem │ ├── _csiSystemTable.gsp │ ├── _form.gsp │ ├── _jobGroupWeight.gsp │ ├── _jobGroupWeights.gsp │ ├── create.gsp │ ├── edit.gsp │ ├── index.gsp │ └── show.gsp │ ├── detailAnalysis │ └── show.gsp │ ├── distributionChart │ ├── _distributionChart.gsp │ └── show.gsp │ ├── error.gsp │ ├── event │ ├── _eventTable.gsp │ ├── _form.gsp │ ├── create.gsp │ ├── edit.gsp │ ├── index.gsp │ └── show.gsp │ ├── eventResultDashboard │ ├── _hoverInfo.gsp │ └── showAll.gsp │ ├── graphiteEventSourcePath │ ├── _form.gsp │ ├── _graphiteEventSourcePathTable.gsp │ ├── create.gsp │ ├── edit.gsp │ ├── index.gsp │ └── show.gsp │ ├── graphitePathCsiData │ ├── _graphitePathCsiDataTable.gsp │ └── index.gsp │ ├── graphitePathRawData │ ├── _graphitePathRawDataTable.gsp │ └── index.gsp │ ├── graphiteServer │ ├── _form.gsp │ ├── _graphiteServerTable.gsp │ ├── create.gsp │ ├── edit.gsp │ ├── index.gsp │ └── show.gsp │ ├── highchart │ ├── _adjustChartModal.gsp │ └── _chart.gsp │ ├── highchartPointDetails │ └── listAggregatedResults.gsp │ ├── infrastructureSetup │ ├── _selectServer.gsp │ ├── create.gsp │ └── index.gsp │ ├── job │ ├── _advancedSettingsTab.gsp │ ├── _advancedSettingsTabContent.gsp │ ├── _advancedTab.gsp │ ├── _authTab.gsp │ ├── _blockTab.gsp │ ├── _cancelLink.gsp │ ├── _checkbox.gsp │ ├── _checkboxTooltip.gsp │ ├── _chromeTab.gsp │ ├── _cronExpression.gsp │ ├── _cronInstructions.gsp │ ├── _customTab.gsp │ ├── _editOrCreate.gsp │ ├── _form.gsp │ ├── _inputField.gsp │ ├── _inputFieldTooltip.gsp │ ├── _jobSettingsTab.gsp │ ├── _jobStatusBar.gsp │ ├── _jobStatusBarHoverInfo.gsp │ ├── _jobTable.gsp │ ├── _messages.gsp │ ├── _scriptTab.gsp │ ├── _spofTab.gsp │ ├── _thresholdsTab.gsp │ ├── _timeago.gsp │ ├── _updateHints.gsp │ ├── _variables.gsp │ ├── create.gsp │ ├── edit.gsp │ └── index.gsp │ ├── jobGroup │ ├── _form.gsp │ ├── _jobGroupTable.gsp │ ├── create.gsp │ ├── edit.gsp │ ├── index.gsp │ └── show.gsp │ ├── jobResult │ └── listFailed.gsp │ ├── jobSchedule │ └── schedules.gsp │ ├── layouts │ ├── _footer.gsp │ ├── _layoutOsmContent.gsp │ ├── _optGroupedSelect.gsp │ ├── _responsiveTable.gsp │ └── layoutOsm.gsp │ ├── location │ ├── _locationTable.gsp │ └── index.gsp │ ├── login │ ├── auth.gsp │ └── denied.gsp │ ├── measuredEvent │ ├── _measuredEventTable.gsp │ ├── edit.gsp │ ├── index.gsp │ └── show.gsp │ ├── measurementSetup │ ├── _cancelJobCreationDialog.gsp │ ├── _createJob.gsp │ ├── _createScript.gsp │ ├── _selectLocationAndConnectivity.gsp │ ├── _setJobGroup.gsp │ ├── create.gsp │ └── index.gsp │ ├── osmConfiguration │ ├── edit.gsp │ ├── index.gsp │ └── show.gsp │ ├── page │ ├── _form.gsp │ ├── _pageTable.gsp │ ├── create.gsp │ ├── edit.gsp │ ├── index.gsp │ └── show.gsp │ ├── pageComparison │ ├── _barChart.gsp │ └── show.gsp │ ├── register │ ├── forgotPassword.gsp │ ├── register.gsp │ └── resetPassword.gsp │ ├── registrationCode │ └── index.gsp │ ├── script │ ├── _codemirror.gsp │ ├── _editOrCreate.gsp │ ├── _form.gsp │ ├── _messages.gsp │ ├── _versionControl.gsp │ ├── create.gsp │ ├── edit.gsp │ └── list.gsp │ ├── siteinfo │ ├── about.gsp │ ├── contact.gsp │ └── systeminfo.gsp │ ├── tabularResultPresentation │ ├── _filterJob.gsp │ ├── _listResults.gsp │ ├── _pagination.gsp │ └── listResults.gsp │ ├── templates │ └── _fields │ │ ├── _list.gsp │ │ └── _table.gsp │ ├── user │ ├── create.gsp │ ├── edit.gsp │ ├── index.gsp │ └── show.gsp │ └── webPageTestServer │ ├── _form.gsp │ ├── _webPageTestServerTable.gsp │ ├── create.gsp │ ├── edit.gsp │ ├── index.gsp │ └── show.gsp ├── grailsw ├── grailsw.bat ├── lib └── grails-rt.jar ├── package-lock.json ├── package.json ├── scripts ├── DbmPortable.groovy ├── TestMysql.groovy ├── _Install.groovy ├── _Uninstall.groovy ├── _Upgrade.groovy ├── ci │ ├── building │ │ ├── merge_branch_into_release.sh │ │ ├── merge_release_into_dev_and_master.sh │ │ ├── push_and_tag_dockerimage_travis.sh │ │ ├── push_new_versionnumber.sh │ │ ├── set_new_versionnumber.groovy │ │ └── set_new_versionnumber_travis_dev.groovy │ ├── debug │ │ ├── activate_mysql_slow_query_log.sh │ │ └── deactivate_mysql_slow_query_log.sh │ ├── deploy │ │ ├── blue-green_switch.sh │ │ ├── check_running_tomcat_instance.sh │ │ ├── copy-config-to-host.sh │ │ ├── docker │ │ │ ├── copy_compose_file_to_host.sh │ │ │ ├── prepare_compose_env_file.sh │ │ │ └── run_compose_deployment.sh │ │ ├── post_deployment_activation.sh │ │ ├── run-deployment-script-on-target-host.sh │ │ ├── to_github.sh │ │ └── war_deployment_via_curl.sh │ └── github_deploy_key.enc └── test │ ├── runGebTestsAndOpenReport.sh │ ├── runIntegrationTestsAndOpenReport.sh │ ├── runJasmineTestsAndOpenReport.sh │ ├── runKarma.sh │ └── runUnitTestsAndOpenReport.sh └── src ├── integration-test └── groovy │ ├── GebConfig.groovy │ ├── de │ └── iteratec │ │ └── osm │ │ ├── barchart │ │ └── BarchartAggregationServiceSpec.groovy │ │ ├── csi │ │ ├── CreatingYesNoDataMvsIntegrationSpec.groovy │ │ ├── CsiAggregationUpdateEventCleanupServiceIntegrationSpec.groovy │ │ ├── CsiCalculationIntegrationSpec.groovy │ │ ├── CsiConfigurationIntegrationSpec.groovy │ │ ├── CsiSystemCsiAggregationServiceIntegrationSpec.groovy │ │ ├── JobGroupCsiAggregationServiceIntegrationSpec.groovy │ │ ├── NonTransactionalIntegrationSpec.groovy │ │ ├── PageCsiAggregationServiceIntegrationSpec.groovy │ │ ├── ShopCsiServiceIntegrationSpec.groovy │ │ ├── WeeklyJobGroupIntegrationSpec.groovy │ │ ├── WeeklyPageIntegrationSpec.groovy │ │ ├── WeeklyPageMultipleCsiGroupsIntegrationSpec.groovy │ │ └── WeeklyShopMultipleCsiGroupsIntegrationSpec.groovy │ │ ├── measurement │ │ ├── environment │ │ │ ├── QueueAndJobStatusServiceIntSpec.groovy │ │ │ └── wptserver │ │ │ │ ├── PersistingResultsIntegrationSpec.groovy │ │ │ │ └── PersistingResultsWithCsiIntegrationSpec.groovy │ │ └── schedule │ │ │ ├── HttpRequestServiceMock.groovy │ │ │ ├── JobGroupServiceIntSpec.groovy │ │ │ ├── JobRunServiceIntegrationSpec.groovy │ │ │ └── JobSchedulingServiceIntegrationSpec.groovy │ │ ├── report │ │ └── chart │ │ │ └── CloseExpiredUpdateEventsIntegrationSpec.groovy │ │ └── result │ │ ├── EventResultDashboardServiceIntegrationSpec.groovy │ │ ├── EventResultDashboardServiceLabelsIntegrationSpec.groovy │ │ ├── dao │ │ ├── ApplicationDashboardServiceIntSpec.groovy │ │ ├── EventResultQueryBuilderAverageIntegrationSpec.groovy │ │ ├── EventResultQueryBuilderIntegrationSpec.groovy │ │ ├── EventResultQueryBuilderMedianIntegrationSpec.groovy │ │ ├── QueryAspectsViaBuilderAverageSpec.groovy │ │ ├── QueryAspectsViaBuilderMedianSpec.groovy │ │ ├── QueryAspectsViaBuilderPercentileSpec.groovy │ │ ├── QueryAspectsViaBuilderRawSpec.groovy │ │ └── QueryEventResultsByConnectivityIntegrationSpec.groovy │ │ └── utils │ │ └── EventResultDaoServiceIntegrationSpec.groovy │ └── geb │ ├── CustomUrlGebReportingSpec.groovy │ ├── IgnoreGebLiveTest.groovy │ ├── de │ └── iteratec │ │ └── osm │ │ ├── LoginRedirectAfterAbortedInfrastructureSetupGebSpec.groovy │ │ ├── LoginRedirectAfterInfrastructureSetupGebSpec.groovy │ │ ├── LoginRedirectBeforeInfrastructureSetupGebSpec.groovy │ │ ├── batch │ │ └── BatchActivityListGebSpec.groovy │ │ ├── csi │ │ ├── CsTargetGraphGebSpec.groovy │ │ ├── CsiDashboardDifferentAggregatorsGebSpec.groovy │ │ ├── CsiDashboardGebSpec.groovy │ │ └── PageGebSpec.groovy │ │ ├── measurement │ │ ├── environment │ │ │ ├── BrowserAliasGebSpec.groovy │ │ │ └── BrowserGebSpec.groovy │ │ ├── schedule │ │ │ └── job │ │ │ │ └── JobListGebSpec.groovy │ │ └── script │ │ │ └── ScriptGebSpec.groovy │ │ ├── result │ │ ├── EventResultDashboardAdjustChartGebSpec.groovy │ │ ├── EventResultDashboardGebSpec.groovy │ │ └── EventResultDashboardUserTimingGebSpec.groovy │ │ └── wizard │ │ ├── InfrastructureSetupWithCustomGebSpec.groovy │ │ ├── InfrastructureSetupWithWptGebSpec.groovy │ │ └── MeasurementSetupGebSpec.groovy │ └── pages │ └── de │ └── iteratec │ └── osm │ ├── I18nGebPage.groovy │ ├── LandingPage.groovy │ ├── LoginPage.groovy │ ├── batch │ └── BatchActivityListPage.groovy │ ├── csi │ ├── CsTargetGraphCreatePage.groovy │ ├── CsTargetGraphEditPage.groovy │ ├── CsTargetGraphIndexPage.groovy │ ├── CsTargetGraphShowPage.groovy │ ├── CsiDashboardPage.groovy │ ├── PageCreatePage.groovy │ ├── PageEditPage.groovy │ ├── PageIndexPage.groovy │ └── PageShowPage.groovy │ ├── measurement │ ├── environment │ │ ├── BrowserAliasCreatePage.groovy │ │ ├── BrowserAliasEditPage.groovy │ │ ├── BrowserAliasIndexPage.groovy │ │ ├── BrowserAliasShowPage.groovy │ │ ├── BrowserCreatePage.groovy │ │ ├── BrowserEditPage.groovy │ │ ├── BrowserIndexPage.groovy │ │ ├── BrowserShowPage.groovy │ │ └── script │ │ │ ├── ScriptCreatePage.groovy │ │ │ └── ScriptListPage.groovy │ └── schedule │ │ └── job │ │ ├── JobCreatePage.groovy │ │ └── JobListPage.groovy │ ├── result │ └── EventResultDashboardPage.groovy │ └── wizards │ ├── InfrastructureSetupPage.groovy │ └── MeasurementSetupPage.groovy ├── java └── .gitignore ├── main ├── groovy │ ├── .gitignore │ └── de │ │ └── iteratec │ │ └── osm │ │ ├── annotations │ │ └── RestAction.groovy │ │ ├── api │ │ └── dto │ │ │ ├── ApplicationCsiDto.groovy │ │ │ ├── BatchActivityRowDto.groovy │ │ │ ├── BrowserDto.groovy │ │ │ ├── BrowserInfoDto.groovy │ │ │ ├── ConnectivityProfileDto.groovy │ │ │ ├── CsiByEventResultsDto.groovy │ │ │ ├── CsiConfigurationDto.groovy │ │ │ ├── CsiDto.groovy │ │ │ ├── CsiTranslationDto.groovy │ │ │ ├── DeviceTypeDto.groovy │ │ │ ├── EventResultDto.groovy │ │ │ ├── GraphiteServerDto.groovy │ │ │ ├── JobDto.groovy │ │ │ ├── JobGroupDto.groovy │ │ │ ├── LocationDto.groovy │ │ │ ├── MeasuredEventDto.groovy │ │ │ ├── MeasurementResultDto.groovy │ │ │ ├── PageCsiDto.groovy │ │ │ ├── PageDto.groovy │ │ │ └── WptServerDto.groovy │ │ ├── barchart │ │ ├── BarchartAggregation.groovy │ │ ├── BarchartDTO.groovy │ │ ├── BarchartDatum.groovy │ │ ├── BarchartSeries.groovy │ │ ├── GetBarchartCommand.groovy │ │ └── PageComparisonAggregation.groovy │ │ ├── batch │ │ ├── Activity.groovy │ │ ├── BatchActivityUpdater.groovy │ │ ├── BatchActivityUpdaterDummy.groovy │ │ └── Status.groovy │ │ ├── csi │ │ ├── Contract.groovy │ │ ├── CsiAggregationCachingContainer.groovy │ │ ├── CsiDashboardShowAllCommand.groovy │ │ ├── CsiType.groovy │ │ ├── CsiValue.groovy │ │ ├── NightlyMvCalculation.groovy │ │ ├── RickshawTransformableCsMapping.groovy │ │ ├── UndefinedCsiTypeException.groovy │ │ └── weighting │ │ │ ├── WeightFactor.groovy │ │ │ ├── WeightedCsiValue.groovy │ │ │ └── WeightedValue.groovy │ │ ├── d3Data │ │ ├── BarChartData.groovy │ │ ├── ChartEntry.groovy │ │ ├── D3HtmlCreator.groovy │ │ ├── GetPageComparisonDataCommand.groovy │ │ ├── MatrixViewData.groovy │ │ ├── MatrixViewEntry.groovy │ │ ├── MultiLineChart.groovy │ │ ├── MultiLineChartLineData.groovy │ │ ├── ScheduleChartData.groovy │ │ ├── ScheduleChartJob.groovy │ │ └── TreemapData.groovy │ │ ├── dao │ │ ├── CriteriaAggregator.groovy │ │ └── CriteriaSorting.groovy │ │ ├── de │ │ └── iteratec │ │ │ └── osm │ │ │ └── api │ │ │ ├── CreateEventCommand.groovy │ │ │ ├── MeasurementActivationCommand.groovy │ │ │ ├── NightlyDatabaseCleanupActivationCommand.groovy │ │ │ └── ResultsRequestCommand.groovy │ │ ├── distributionData │ │ ├── DistributionChartDTO.groovy │ │ ├── DistributionTrace.groovy │ │ ├── GetDistributionCommand.groovy │ │ ├── GetViolinchartCommand.groovy │ │ ├── Violin.groovy │ │ └── ViolinChartDTO.groovy │ │ ├── linechart │ │ ├── GetLinechartCommand.groovy │ │ ├── SummaryLabel.groovy │ │ ├── TimeSeries.groovy │ │ ├── TimeSeriesChartDTO.groovy │ │ ├── TimeSeriesDataPoint.groovy │ │ └── TimeSeriesDataPointWptInfo.groovy │ │ ├── measurement │ │ ├── environment │ │ │ ├── LocationWithXmlNode.groovy │ │ │ └── wptserver │ │ │ │ ├── OsmResultPersistanceException.groovy │ │ │ │ ├── Protocol.groovy │ │ │ │ └── WptResultXml.groovy │ │ ├── schedule │ │ │ ├── CronExpressionFormatter.groovy │ │ │ └── FailedJobResultDTO.groovy │ │ └── script │ │ │ ├── PlaceholdersUtility.groovy │ │ │ └── ScriptParser.groovy │ │ ├── report │ │ ├── chart │ │ │ ├── AggregationType.groovy │ │ │ ├── ChartingLibrary.groovy │ │ │ ├── DataType.java │ │ │ ├── OsmChartAxis.groovy │ │ │ ├── OsmChartGraph.groovy │ │ │ ├── OsmChartPoint.groovy │ │ │ ├── OsmRickshawChart.groovy │ │ │ ├── RepresentableWptResult.groovy │ │ │ ├── RickshawHtmlCreater.groovy │ │ │ ├── WptEventResultInfo.groovy │ │ │ └── page │ │ │ │ └── EntryAndFollowDto.groovy │ │ ├── external │ │ │ ├── GraphiteComunicationFailureException.java │ │ │ ├── GraphitePathName.groovy │ │ │ ├── GraphiteSocket.java │ │ │ ├── GraphiteTCPSocket.groovy │ │ │ ├── GraphiteUDPSocket.groovy │ │ │ ├── MockedGraphiteSocket.groovy │ │ │ └── provider │ │ │ │ ├── DefaultGraphiteSocketProvider.groovy │ │ │ │ └── GraphiteSocketProvider.java │ │ └── ui │ │ │ ├── EventResultListing.groovy │ │ │ ├── EventResultListingRow.groovy │ │ │ ├── PaginationListing.groovy │ │ │ └── PaginationListingRow.groovy │ │ ├── result │ │ ├── CachedView.groovy │ │ ├── Contract.groovy │ │ ├── DetailAnalysisDashboardShowCommand.groovy │ │ ├── DeviceType.groovy │ │ ├── ErQueryParams.groovy │ │ ├── EventResultDashboardShowAllCommand.groovy │ │ ├── GraphLabel.groovy │ │ ├── JobResultStatus.groovy │ │ ├── Measurand.groovy │ │ ├── MeasurandGroup.groovy │ │ ├── MvQueryParams.groovy │ │ ├── OperatingSystem.groovy │ │ ├── PerformanceAspectType.groovy │ │ ├── SelectedMeasurand.groovy │ │ ├── SelectedMeasurandType.groovy │ │ ├── TabularResultEventResultsCommandBase.groovy │ │ ├── TabularResultListResultsForSpecificJobCommand.groovy │ │ ├── TabularResultListsResultCommand.groovy │ │ ├── ThresholdResult.groovy │ │ ├── TimeSeriesShowCommandBase.groovy │ │ ├── Unit.groovy │ │ ├── UserTimingType.groovy │ │ ├── WptStatus.groovy │ │ ├── WptXmlResultVersion.groovy │ │ ├── dao │ │ │ ├── EventResultProjection.groovy │ │ │ ├── EventResultQueryBuilder.groovy │ │ │ ├── MeasurandDto.groovy │ │ │ ├── PerformanceAspectDto.groovy │ │ │ ├── PerformanceAspectTypeDto.groovy │ │ │ └── query │ │ │ │ ├── AggregationUtil.groovy │ │ │ │ ├── AspectUtil.groovy │ │ │ │ ├── EventResultQueryExecutor.groovy │ │ │ │ ├── MeasurandTrim.groovy │ │ │ │ ├── ProjectionProperty.groovy │ │ │ │ ├── TrimQualifier.groovy │ │ │ │ ├── projector │ │ │ │ ├── EventResultProjector.groovy │ │ │ │ ├── MeasurandAverageDataProjector.groovy │ │ │ │ ├── MeasurandRawDataProjector.groovy │ │ │ │ ├── UserTimingAverageDataProjector.groovy │ │ │ │ └── UserTimingRawDataProjector.groovy │ │ │ │ ├── transformer │ │ │ │ ├── EventResultTransformer.groovy │ │ │ │ ├── MeasurandAverageDataTransformer.groovy │ │ │ │ ├── MeasurandMedianDataTransformer.groovy │ │ │ │ ├── MeasurandPercentileDataTransformer.groovy │ │ │ │ ├── MeasurandRawDataTransformer.groovy │ │ │ │ ├── UserTimingAverageDataTransformer.groovy │ │ │ │ ├── UserTimingMedianDataTransformer.groovy │ │ │ │ ├── UserTimingPercentileDataTransformer.groovy │ │ │ │ └── UserTimingRawDataTransformer.groovy │ │ │ │ └── trimmer │ │ │ │ ├── EventResultTrimmer.groovy │ │ │ │ ├── MeasurandAverageDataTrimmer.groovy │ │ │ │ ├── MeasurandRawDataTrimmer.groovy │ │ │ │ └── UserTimingDataTrimmer.groovy │ │ └── dto │ │ │ ├── AggregationChartDTO.groovy │ │ │ ├── AggregationChartSeriesDTO.groovy │ │ │ └── JobGroupDTO.groovy │ │ └── util │ │ ├── AnnotationUtil.groovy │ │ ├── Constants.groovy │ │ ├── ControllerUtils.groovy │ │ ├── DataIntegrityViolationExpectionUtil.groovy │ │ ├── LoggedExecutionTimes.groovy │ │ ├── MessagePropertiesTrait.groovy │ │ ├── MethodToMock.groovy │ │ └── ParameterBindingUtility.groovy ├── resources │ ├── Default_CSI_Mappings.csv │ ├── OsmCiPipeCheck.groovy.template │ └── public │ │ ├── .gitkeep │ │ └── i18n │ │ └── README.md └── templates │ └── scaffolding │ ├── AsyncController.groovy │ ├── AsyncSpec.groovy │ ├── Controller.groovy │ ├── ScaffoldedController.groovy │ ├── Spec.groovy │ ├── create.gsp │ ├── edit.gsp │ ├── index.gsp │ └── show.gsp └── test ├── groovy └── de │ └── iteratec │ └── osm │ ├── ConfigServiceSpec.groovy │ ├── InMemoryConfigServiceSpec.groovy │ ├── OsmStateServiceSpec.groovy │ ├── SelectedMeasurandSpec.groovy │ ├── SelectedMeasurandTypeSpec.groovy │ ├── api │ ├── CsiApiControllerSpec.groovy │ ├── CsiByEventResultsServiceSpec.groovy │ ├── DetailDataApiControllerSpec.groovy │ ├── EventCreationViaRestApiSpec.groovy │ ├── GeneralMeasurementApiControllerSpec.groovy │ ├── MeasurementActivationViaRestApiSpec.groovy │ ├── NightlyCleanupActivationViaRestApiSpec.groovy │ ├── RestApiInterceptorSpec.groovy │ ├── ResultsBetweenCmdMeasuredEventBindingSpec.groovy │ ├── ResultsBetweenCmdPageBindingSpec.groovy │ └── json │ │ └── ResultTestsSpec.groovy │ ├── batch │ ├── BatchActivityServiceSpec.groovy │ └── BatchActivityUpdaterSpec.groovy │ ├── csi │ ├── BrowserConnectivityWeightSpec.groovy │ ├── CsTargetGraphSpec.groovy │ ├── CsTargetValueControllerSpec.groovy │ ├── CsiConfigIOControllerSpec.groovy │ ├── CsiConfigurationControllerSpec.groovy │ ├── CsiDashboardControllerSpec.groovy │ ├── CsiDaySpec.groovy │ ├── CsiSystemCsiAggregationServiceSpec.groovy │ ├── CsiSystemSpec.groovy │ ├── CustomerSatisfactionHighChartServiceSpec.groovy │ ├── CustomerSatisfactionWeightServiceSpec.groovy │ ├── DefaultTimeToCsMappingDeleteSpec.groovy │ ├── EventCsiAggregationServiceSpec.groovy │ ├── JobGroupWeightSpec.groovy │ ├── MeanCalcServiceSpec.groovy │ ├── OsmConfigCacheServiceSpec.groovy │ ├── TestDataUtil.groovy │ ├── TimeToCsMappingServiceSpec.groovy │ ├── UpdateEventResultDependentCsiAggregationsSpec.groovy │ ├── transformation │ │ └── DefaultTimeToCsMappingServiceSpec.groovy │ └── weighting │ │ └── WeightedAverageCalculationSpec.groovy │ ├── d3 │ └── D3ChartTagLibSpec.groovy │ ├── d3Data │ ├── BarChartDataSpec.groovy │ ├── MatrixViewDataSpec.groovy │ ├── MatrixViewEntrySpec.groovy │ ├── MultiLineChartLineDataSpec.groovy │ ├── MultiLineChartSpec.groovy │ ├── ScheduleChartDataSpec.groovy │ ├── ScheduleChartJobSpec.groovy │ └── TreemapDataSpec.groovy │ ├── integrations │ └── CiPipeServiceSpec.groovy │ ├── measurement │ ├── environment │ │ ├── BrowserServiceSpec.groovy │ │ ├── LocationSpec.groovy │ │ ├── WptServerServiceSpec.groovy │ │ └── wptserver │ │ │ ├── FetchResultsFromWptserverSpec.groovy │ │ │ ├── HttpRequestServiceSpec.groovy │ │ │ ├── PersistConnectivityInNewEventResultSpec.groovy │ │ │ ├── PersistScreenshotDependentWptMetricsSpec.groovy │ │ │ ├── PersistingLocationsSpec.groovy │ │ │ ├── PersistingNewEventResultsSpec.groovy │ │ │ ├── PersistingNewEventResultsWithNoMedianOptionTestSpec.groovy │ │ │ ├── ResultXmlProcessingSpec.groovy │ │ │ ├── ResultXmlWptServer219Spec.groovy │ │ │ └── WptInfrastructurePersistenceWithIncomingResultsSpec.groovy │ ├── schedule │ │ ├── ConnectivityProfileControllerSpec.groovy │ │ ├── ConnectivityProfileDaoServiceSpec.groovy │ │ ├── ConnectivityProfileServiceSpec.groovy │ │ ├── GraphitePathRawDataSpec.groovy │ │ ├── JobControllerSpec.groovy │ │ ├── JobDaoServiceSpec.groovy │ │ ├── JobGroupServiceSpec.groovy │ │ ├── JobGroupSpec.groovy │ │ ├── JobServiceSpec.groovy │ │ ├── JobSpec.groovy │ │ ├── JobStatisticServiceSpec.groovy │ │ └── PlaceholdersUtilitySpec.groovy │ └── script │ │ ├── ScriptParserTestSpec.groovy │ │ ├── ScriptServiceSpec.groovy │ │ └── ScriptSpec.groovy │ ├── persistence │ └── DbCleanupServiceSpec.groovy │ ├── report │ ├── chart │ │ ├── CsiAggregationDaoServiceSpec.groovy │ │ ├── CsiAggregationSpec.groovy │ │ ├── CsiAggregationUpdateEventDaoServiceSpec.groovy │ │ ├── CsiAggregationUtilServiceSpec.groovy │ │ ├── EventCreationSpec.groovy │ │ ├── OsmChartPointSpec.groovy │ │ ├── OsmChartProcessingServiceSpec.groovy │ │ └── OsmChartTagLibSpec.groovy │ ├── external │ │ ├── FilterResultsToReportSpec.groovy │ │ ├── GraphiteEventServiceSpec.groovy │ │ ├── GraphitePathNameSpec.groovy │ │ ├── GraphiteReportServiceSpec.groovy │ │ ├── JobHealthReportServiceSpec.groovy │ │ ├── MetricReportingServiceSpec.groovy │ │ └── QuartzControlledGrailsReportsSpec.groovy │ └── ui │ │ ├── EventResultListingSpec.groovy │ │ └── PaginationListingSpec.groovy │ ├── result │ ├── AggregationControllerSpec.groovy │ ├── CachedViewSpec.groovy │ ├── ContractSpec.groovy │ ├── CsiValueProcessingSpec.groovy │ ├── CsiValueServiceSpec.groovy │ ├── EventResultDashboardControllerSpec.groovy │ ├── EventResultDashboardServiceSpec.groovy │ ├── JobResultSpec.groovy │ ├── MvQueryParamsSpec.groovy │ ├── PageServiceSpec.groovy │ ├── PaginationServiceSpec.groovy │ ├── PerformanceAspectSpec.groovy │ ├── QueueDashboardControllerSpec.groovy │ ├── ResultSelectionControllerSpec.groovy │ ├── ResultSelectionInformationServiceSpec.groovy │ ├── TabularResultEventResultCommandBaseSpec.groovy │ ├── ThresholdServiceSpec.groovy │ ├── ThresholdSpec.groovy │ ├── TimeSeriesShowCommandBaseSpec.groovy │ ├── UserTimingSpec.groovy │ ├── WptResultValidationSpec.groovy │ └── dao │ │ └── query │ │ └── AggregationUtilTest.groovy │ ├── system │ ├── LocationHealthCheckDaoServiceSpec.groovy │ ├── LocationHealthCheckServiceSpec.groovy │ ├── MissingJobResultCheckServiceSpec.groovy │ ├── MissingJobResultCheckSpec.groovy │ └── SendLocationHealthChecksToGraphiteSpec.groovy │ └── util │ ├── ControllerUtilsSpec.groovy │ ├── CronExpressionControllerSpec.groovy │ ├── OsmTestLogin.groovy │ ├── ParameterBindingUtilitySpec.groovy │ ├── PerformanceLoggingServiceSpec.groovy │ └── ServiceMocker.groovy ├── js ├── karma.conf.js └── specs │ ├── ChartLabelUtilSpec.js │ ├── DefaultMappingCsvValidatorSpec.js │ ├── OsmGlobalOnReadyUtilsSpec.js │ ├── aggregationChartDataSpec.js │ ├── chartColorProviderSpec.js │ └── pageComparisonChartDataSpec.js └── resources ├── CsiData ├── BROWSER_CONNECTIVITY_COMBINATION_weights.csv ├── BROWSER_CONNECTIVITY_COMBINATION_weights_should_fail.csv ├── DefaultMappings.csv ├── HOUROFDAY_weights.csv ├── HOUROFDAY_weights_should_fail.csv ├── HOUROFDAY_weights_should_fail_2.csv ├── PAGE_weights.csv ├── PAGE_weights_should_fail.csv ├── TimeToCsMapping │ ├── expectedValues.csv │ └── timeToCsMappings.csv ├── calcJobGroupCsiFromCsvData.groovy ├── weekly_page.csv ├── weekly_page.csv.bak ├── weekly_page.csv.bak2 ├── weekly_page_KW50_2012.csv └── weekly_page_multiple_csi_groups.csv ├── GraphiteEvents └── GraphiteEventServiceSpec_retreive_events.json ├── TestDataConfig.groovy ├── WptLocationXmls └── locationResponse.xml └── WptResultXmls ├── BEFORE_MULTISTEP_1Run_JustFirstView.xml ├── BEFORE_MULTISTEP_1Run_NotCsiRelevantCauseDocTimeTooHighResponse.xml ├── BEFORE_MULTISTEP_1Run_WithVideo.xml ├── BEFORE_MULTISTEP_1Run_WithoutVideo.xml ├── BEFORE_MULTISTEP_3Runs.xml ├── BEFORE_MULTISTEP_3Runs_CsiRelevant.xml ├── BEFORE_MULTISTEP_3Runs_WithPageName_CsiRelevant.xml ├── BEFORE_MULTISTEP_5Runs_WithVideo.xml ├── BEFORE_MULTISTEP_Error_testCompletedButThereWereNoSuccessfulResults.xml ├── DEV_EXAMPLE_JOB_FIREFOX_17JUL2017_1Run_3Events.xml ├── MULTISTEP_1Run_5Steps.xml ├── MULTISTEP_2Run.xml ├── MULTISTEP_Error_Failure_In_Step.xml ├── MULTISTEP_FORK_ITERATEC_1Run_11Events_JustFirstView.xml ├── MULTISTEP_FORK_ITERATEC_1Run_2EventNamesWithPagePrefix_JustFirstView.xml ├── MULTISTEP_FORK_ITERATEC_1Run_2EventNames_FaultyLoadTime_PagePrefix.xml ├── MULTISTEP_FORK_ITERATEC_1Run_2EventNames_FaultyResultCode_PagePrefix.xml ├── MULTISTEP_FORK_ITERATEC_1Run_2EventNames_FaultyTTFB_PagePrefix.xml ├── MULTISTEP_FORK_ITERATEC_1Run_2EventNames_PagePrefix.xml ├── MULTISTEP_FORK_ITERATEC_1Run_3Events_JustFirstView_WithVideo.xml ├── MULTISTEP_FORK_ITERATEC_1Run_3Events_JustFirstView_WithoutVideo.xml ├── MULTISTEP_FORK_ITERATEC_1Run_WithVideo.xml ├── MULTISTEP_FORK_ITERATEC_3Runs_6EventNames.xml ├── MULTISTEP_FORK_ITERATEC_3Runs_6EventNames_WithPageName.xml ├── MULTISTEP_FORK_ITERATEC_5Runs_3Events_JustFirstView_WithVideo.xml ├── MULTISTEP_interactiveMetrics.xml ├── README ├── WPT_EXAMPLE_CHROME_TTI_1Run_1Event.xml └── firstPaint.xml /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-minimal -------------------------------------------------------------------------------- /docker/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # prepare osm config respective set env variables 4 | OSM_CONFIG_TARGET_LOCATION="${OSM_CONFIG_HOME}/OpenSpeedMonitor-config.yml" 5 | 6 | echo "complete osm config file gets prepared" 7 | dockerize -template $OSM_CONFIG_TARGET_LOCATION.j2:$OSM_CONFIG_TARGET_LOCATION 8 | 9 | # start tomcat 10 | java -Dgrails.env=prod -Dosm_config_location=${OSM_CONFIG_TARGET_LOCATION} -DlogToFile=true -jar $OSM_HOME/OpenSpeedMonitor*.war 11 | -------------------------------------------------------------------------------- /docker/osm-with-wpt/locations.ini: -------------------------------------------------------------------------------- 1 | 2 | [locations] 3 | 1=Local_Docker_Location 4 | default=Local_Docker_Location 5 | 6 | [Local_Docker_Location] 7 | 1=Local_Docker 8 | label="Local Docker Location" 9 | 10 | [Local_Docker] 11 | browser=Chrome 12 | latency=0 13 | label="Local Docker with Chrome" 14 | 15 | [foo] 16 | -------------------------------------------------------------------------------- /frontend/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /frontend/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | 3 | export const APP_COMPONENT_SELECTOR = 'osm-app'; 4 | 5 | @Component({ 6 | selector: APP_COMPONENT_SELECTOR, 7 | template: '', 8 | styleUrls: [] 9 | }) 10 | export class AppComponent { 11 | constructor() { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /frontend/src/app/enums/chart-commons.enum.ts: -------------------------------------------------------------------------------- 1 | export enum ChartCommons { 2 | TRANSITION_DURATION = 500, 3 | BAR_BAND = 40, 4 | BAR_GAP = 5, 5 | COMPONENT_MARGIN = 15, 6 | CHART_HEADER_HEIGHT = 40, 7 | COLOR_PREVIEW_SIZE = 10, 8 | COLOR_PREVIEW_MARGIN = 5, 9 | LABEL_HEIGHT = 18 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/app/enums/performance-aspect-types.enum.ts: -------------------------------------------------------------------------------- 1 | export enum PerformanceAspectTypes { 2 | PAGE_CONSTRUCTION_STARTED = "PAGE_CONSTRUCTION_STARTED", 3 | PAGE_SHOWS_USEFUL_CONTENT = "PAGE_SHOWS_USEFUL_CONTENT", 4 | PAGE_IS_USABLE = "PAGE_IS_USABLE" 5 | } 6 | -------------------------------------------------------------------------------- /frontend/src/app/enums/ui-component.enum.ts: -------------------------------------------------------------------------------- 1 | export enum UiComponent { 2 | APPLICATION, PAGE, LOCATION, CONNECTIVITY, MEASURAND 3 | } 4 | -------------------------------------------------------------------------------- /frontend/src/app/enums/unit.enum.ts: -------------------------------------------------------------------------------- 1 | export enum Unit { 2 | MEBIBYTES = "MiB", 3 | SECONDS = "s" 4 | } 5 | -------------------------------------------------------------------------------- /frontend/src/app/enums/url.enum.ts: -------------------------------------------------------------------------------- 1 | export enum URL { 2 | APPLICATIONS = '/resultSelection/getJobGroups', 3 | APPLICATIONS_AND_PAGES = '/jobGroup/getJobGroupsWithPages', 4 | EVENTS_AND_PAGES = '/resultSelection/getMeasuredEvents', 5 | LOCATIONS_AND_BROWSERS = '/resultSelection/getLocations', 6 | CONNECTIVITIES = '/resultSelection/getConnectivityProfiles', 7 | MEASURANDS = '/resultSelection/getMeasurands', 8 | USER_TIMINGS = '/resultSelection/getUserTimings', 9 | HERO_TIMINGS = '/resultSelection/getHeroTimings', 10 | RESULT_COUNT = '/resultSelection/getResultCount', 11 | AGGREGATION_BARCHART_DATA = '/aggregation/getBarchartData', 12 | EVENT_RESULT_DASHBOARD_LINECHART_DATA = '/eventResultDashboard/getLinechartData', 13 | DISTRIBUTION_VIOLINCHART_DATA = '/distributionChart/getViolinchartData' 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/app/models/browser.model.ts: -------------------------------------------------------------------------------- 1 | export interface BrowserDTO { 2 | id: number; 3 | name: string; 4 | } 5 | 6 | export class Browser implements BrowserDTO { 7 | id: number; 8 | name: string; 9 | 10 | constructor (dto: BrowserDTO) { 11 | this.id = dto.id; 12 | this.name = dto.name; 13 | } 14 | } 15 | 16 | export interface BrowserInfoDto { 17 | browserId: number 18 | browserName: string 19 | operatingSystem: string 20 | deviceType: DeviceType 21 | } 22 | 23 | export interface DeviceType { 24 | name: string 25 | icon: string 26 | } 27 | -------------------------------------------------------------------------------- /frontend/src/app/models/connectivity.model.ts: -------------------------------------------------------------------------------- 1 | export interface ConnectivityDTO { 2 | id: number; 3 | name: string; 4 | } 5 | 6 | export class Connectivity implements ConnectivityDTO { 7 | id: number; 8 | name: string; 9 | 10 | constructor (dto: ConnectivityDTO) { 11 | this.id = dto.id; 12 | this.name = dto.name; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/app/models/csi.model.ts: -------------------------------------------------------------------------------- 1 | import {parseDate} from "../utils/date.util"; 2 | 3 | export interface CsiDTO { 4 | date?: string | Date, 5 | csiDocComplete?: number 6 | } 7 | 8 | export class Csi implements CsiDTO { 9 | date: Date; 10 | csiDocComplete: number; 11 | 12 | constructor(dto: CsiDTO) { 13 | this.date = parseDate(dto.date || new Date(0)); 14 | this.csiDocComplete = dto.csiDocComplete; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /frontend/src/app/models/global-osm-namespace.model.ts: -------------------------------------------------------------------------------- 1 | export interface GlobalOsmNamespace { 2 | i18n: { 3 | lang: 'de' | 'en' 4 | }, 5 | user: { 6 | loggedIn: boolean 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /frontend/src/app/models/loading.model.ts: -------------------------------------------------------------------------------- 1 | export interface Loading { 2 | isLoading: boolean 3 | } 4 | -------------------------------------------------------------------------------- /frontend/src/app/models/location.model.ts: -------------------------------------------------------------------------------- 1 | import {Browser} from "./browser.model"; 2 | 3 | export interface LocationDTO { 4 | id: number; 5 | name: string; 6 | parent: Browser; 7 | } 8 | 9 | export class Location implements LocationDTO { 10 | id: number; 11 | name: string; 12 | parent: Browser; 13 | 14 | constructor (dto: LocationDTO) { 15 | this.id = dto.id; 16 | this.name = dto.name; 17 | this.parent = dto.parent; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frontend/src/app/models/measurand.model.ts: -------------------------------------------------------------------------------- 1 | import {Loading} from "./loading.model"; 2 | import {PerformanceAspectType} from "./perfomance-aspect.model"; 3 | 4 | export interface SelectableMeasurand { 5 | kind: "selectable-measurand" 6 | name: string 7 | id: string 8 | isUserTiming?: boolean 9 | } 10 | 11 | export interface MeasurandGroup extends Loading { 12 | name: string, 13 | values: SelectableMeasurand[] 14 | } 15 | 16 | export type Measurand = PerformanceAspectType | SelectableMeasurand 17 | -------------------------------------------------------------------------------- /frontend/src/app/models/measured-event.model.ts: -------------------------------------------------------------------------------- 1 | import { Page } from "./page.model"; 2 | 3 | export interface MeasuredEventDTO { 4 | id: number; 5 | name: string; 6 | parent: Page; 7 | } 8 | 9 | export class MeasuredEvent implements MeasuredEventDTO { 10 | id: number; 11 | name: string; 12 | parent: Page; 13 | 14 | constructor (dto: MeasuredEventDTO) { 15 | this.id = dto.id; 16 | this.name = dto.name; 17 | this.parent = dto.parent; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frontend/src/app/models/page.model.ts: -------------------------------------------------------------------------------- 1 | export interface PageDTO { 2 | name: string 3 | id: number 4 | 5 | } 6 | export class Page implements PageDTO { 7 | id: number; 8 | name: string; 9 | 10 | constructor (dto: PageDTO) { 11 | this.id = dto.id; 12 | this.name = dto.name; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/app/models/perfomance-aspect.model.ts: -------------------------------------------------------------------------------- 1 | import {SelectableMeasurand} from "./measurand.model"; 2 | import {BrowserInfoDto} from "./browser.model"; 3 | 4 | 5 | export interface PerformanceAspect { 6 | id: number 7 | pageId: number 8 | applicationId: number 9 | browserId: number 10 | measurand: SelectableMeasurand 11 | performanceAspectType: PerformanceAspectType 12 | persistent: boolean 13 | } 14 | 15 | export type ExtendedPerformanceAspect = PerformanceAspect & BrowserInfoDto 16 | 17 | export interface PerformanceAspectType { 18 | kind: "performance-aspect-type" 19 | name: string 20 | icon: string 21 | unit: string 22 | } 23 | -------------------------------------------------------------------------------- /frontend/src/app/models/response-with-loading-state.model.ts: -------------------------------------------------------------------------------- 1 | export interface ResponseWithLoadingState { 2 | isLoading: boolean, 3 | data: T 4 | } 5 | -------------------------------------------------------------------------------- /frontend/src/app/modules/aggregation/aggregation.component.scss: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /frontend/src/app/modules/aggregation/services/barchart-data.service.spec.ts: -------------------------------------------------------------------------------- 1 | import {TestBed} from '@angular/core/testing'; 2 | import {BarchartDataService} from './barchart-data.service'; 3 | import {HttpClientTestingModule} from '@angular/common/http/testing'; 4 | import {AggregationChartDataService} from './aggregation-chart-data.service'; 5 | 6 | 7 | describe('BarchartDataService', () => { 8 | beforeEach(() => TestBed.configureTestingModule({ 9 | providers: [ 10 | BarchartDataService, 11 | AggregationChartDataService 12 | ], 13 | imports: [HttpClientTestingModule] 14 | })); 15 | 16 | it('should be created', () => { 17 | const service: BarchartDataService = TestBed.get(BarchartDataService); 18 | expect(service).toBeTruthy(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /frontend/src/app/modules/application-dashboard/application-dashboard.module.spec.ts: -------------------------------------------------------------------------------- 1 | import { ApplicationDashboardModule } from './application-dashboard.module'; 2 | 3 | describe('ApplicationDashboardModule', () => { 4 | let applicationDashboardModule: ApplicationDashboardModule; 5 | 6 | beforeEach(() => { 7 | applicationDashboardModule = new ApplicationDashboardModule(); 8 | }); 9 | 10 | it('should create an instance', () => { 11 | expect(applicationDashboardModule).toBeTruthy(); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /frontend/src/app/modules/application-dashboard/components/application-select/application-select.component.html: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /frontend/src/app/modules/application-dashboard/components/application-select/application-select.component.scss: -------------------------------------------------------------------------------- 1 | .select-application-header { 2 | border: none; 3 | background-color: transparent; 4 | } 5 | 6 | .select-application-header-triangle { 7 | margin-left: 10px; 8 | } 9 | -------------------------------------------------------------------------------- /frontend/src/app/modules/application-dashboard/components/application-select/application-select.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, EventEmitter, Input, Output} from '@angular/core'; 2 | import {Application, ApplicationDTO} from "../../../../models/application.model"; 3 | 4 | @Component({ 5 | selector: 'osm-application-select', 6 | templateUrl: './application-select.component.html', 7 | styleUrls: ['./application-select.component.scss'] 8 | }) 9 | export class ApplicationSelectComponent { 10 | @Output() selectedApplicationChange: EventEmitter = new EventEmitter(); 11 | @Input() applications: Application[]; 12 | @Input() selectedApplication: Application; 13 | 14 | constructor() { 15 | } 16 | 17 | setApplication(application: Application) { 18 | this.selectedApplicationChange.emit(application) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /frontend/src/app/modules/application-dashboard/components/csi-graph/csi-graph.component.html: -------------------------------------------------------------------------------- 1 |
2 | 4 | 5 | 6 | 7 | 8 |
9 | -------------------------------------------------------------------------------- /frontend/src/app/modules/application-dashboard/components/page-metric/page-metric.component.html: -------------------------------------------------------------------------------- 1 |
3 | 4 |
{{ isAvailable() ? value : "n/a"}}
5 |
{{ determineUnit(metric?.unit) }}
6 |
{{ 'frontend.de.iteratec.osm.performance-aspect.' + metric?.name + '.user-centric-question' | translate }}
7 |
8 |
9 | -------------------------------------------------------------------------------- /frontend/src/app/modules/application-dashboard/components/page-metric/page-metric.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../../styles/colors"; 2 | 3 | .metric { 4 | margin: 10px 0; 5 | } 6 | 7 | .metric-icon { 8 | display: inline-block; 9 | width: 25px; 10 | text-align: left; 11 | font-size: 18px; 12 | color: $color-text-medium; 13 | } 14 | 15 | .metric-value { 16 | display: inline-block; 17 | min-width: 45px; 18 | text-align: right; 19 | font: { 20 | size: 18px; 21 | weight: bold; 22 | } 23 | color: $color-text-medium; 24 | } 25 | 26 | .metric-unit { 27 | display: inline-block; 28 | margin-left: 3px; 29 | font-size: 14px; 30 | color: $color-text-medium; 31 | } 32 | 33 | .metric-description { 34 | min-width: 120px; 35 | font-size: 12px; 36 | color: $color-text-light; 37 | } 38 | -------------------------------------------------------------------------------- /frontend/src/app/modules/application-dashboard/components/page-metric/page-metric.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input} from '@angular/core'; 2 | import {Unit} from "../../../../enums/unit.enum"; 3 | import {PerformanceAspectType} from "../../../../models/perfomance-aspect.model"; 4 | 5 | @Component({ 6 | selector: 'osm-page-metric', 7 | templateUrl: './page-metric.component.html', 8 | styleUrls: ['./page-metric.component.scss'] 9 | }) 10 | 11 | export class PageMetricComponent { 12 | @Input() metric: PerformanceAspectType; 13 | @Input() value: string; 14 | 15 | Unit: typeof Unit = Unit; 16 | 17 | public isAvailable(): boolean { 18 | return this.value !== ''; 19 | } 20 | 21 | determineUnit(unit: string): string { 22 | if (unit === 'ms') { 23 | return Unit.SECONDS 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /frontend/src/app/modules/application-dashboard/components/page/page.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../../styles/colors"; 2 | 3 | .page-metrics { 4 | display: flex; 5 | } 6 | 7 | i.icon-right { 8 | float: right; 9 | } 10 | 11 | osm-csi-value-medium { 12 | flex: 1 1 0; 13 | padding-right: 20px; 14 | } 15 | 16 | .metric-list { 17 | flex: 1 1 0; 18 | } 19 | 20 | .aspect-management { 21 | float: right; 22 | } 23 | -------------------------------------------------------------------------------- /frontend/src/app/modules/application-dashboard/models/failing-job-statistic.model.ts: -------------------------------------------------------------------------------- 1 | export interface FailingJobStatisticDTO { 2 | minimumFailedJobSuccessRate: number; 3 | numberOfFailingJobs: number; 4 | } 5 | 6 | export class FailingJobStatistic implements FailingJobStatisticDTO { 7 | minimumFailedJobSuccessRate: number; 8 | numberOfFailingJobs: number; 9 | 10 | constructor(dto: FailingJobStatisticDTO) { 11 | this.minimumFailedJobSuccessRate = dto.minimumFailedJobSuccessRate; 12 | this.numberOfFailingJobs = dto.numberOfFailingJobs; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/app/modules/application-dashboard/models/graphite-server.model.ts: -------------------------------------------------------------------------------- 1 | export interface GraphiteServerDTO { 2 | id: number; 3 | address: string; 4 | port: number; 5 | protocol: string; 6 | webAppAddress: string; 7 | prefix: string; 8 | } 9 | 10 | export class GraphiteServer implements GraphiteServerDTO { 11 | id: number; 12 | address: string; 13 | port: number; 14 | protocol: string; 15 | webAppAddress: string; 16 | prefix: string; 17 | 18 | constructor(dto: GraphiteServerDTO) { 19 | this.id = dto.id; 20 | this.address = dto.address; 21 | this.port = dto.port; 22 | this.protocol = dto.protocol; 23 | this.webAppAddress = dto.webAppAddress; 24 | this.prefix = dto.prefix; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /frontend/src/app/modules/application-dashboard/models/location.model.ts: -------------------------------------------------------------------------------- 1 | export interface BrowserDto { 2 | id: number 3 | name: string 4 | } 5 | export interface LocationDto { 6 | id: Number 7 | name: string 8 | parent: BrowserDto 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/app/modules/application-dashboard/models/page-csi.model.ts: -------------------------------------------------------------------------------- 1 | export interface PageCsiDto { 2 | pageId: number, 3 | date: string, 4 | csiDocComplete: number 5 | } 6 | -------------------------------------------------------------------------------- /frontend/src/app/modules/application-dashboard/models/page-metrics.model.ts: -------------------------------------------------------------------------------- 1 | export interface PageMetricsDto { 2 | pageId: number; 3 | pageName: string; 4 | PAGE_CONSTRUCTION_STARTED: number; 5 | PAGE_IS_USABLE: number; 6 | PAGE_SHOWS_USEFUL_CONTENT: number; 7 | } 8 | -------------------------------------------------------------------------------- /frontend/src/app/modules/aspect-configuration/aspect-configuration.component.scss: -------------------------------------------------------------------------------- 1 | a { 2 | margin: 0 10px 20px 0; 3 | } 4 | 5 | .grid-container { 6 | display: grid; 7 | grid-template-columns: repeat(auto-fill, minmax(460px, 1fr)); 8 | margin: 10px 0 0 0; 9 | 10 | osm-aspect-metrics { 11 | margin: 10px 0 20px 10px; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/app/modules/aspect-configuration/components/edit-aspect-metrics/edit-aspect-metrics.component.scss: -------------------------------------------------------------------------------- 1 | a { 2 | margin: 0 10px 20px 0; 3 | } 4 | 5 | .grid-container { 6 | display: grid; 7 | grid-template-columns: 1fr minmax(300px, 3fr); 8 | margin: 10px 0 0 0; 9 | } 10 | 11 | .btn-aspect-config { 12 | margin: 15px 0 0 0; 13 | } 14 | -------------------------------------------------------------------------------- /frontend/src/app/modules/distribution/distribution.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/frontend/src/app/modules/distribution/distribution.component.scss -------------------------------------------------------------------------------- /frontend/src/app/modules/distribution/models/distribution.model.ts: -------------------------------------------------------------------------------- 1 | export interface DistributionDTO { 2 | identifier: string; 3 | label: string; 4 | jobGroup: string; 5 | measurand: string; 6 | page: string; 7 | data: number[]; 8 | median: number; 9 | } 10 | 11 | export class Distribution implements DistributionDTO { 12 | identifier: string; 13 | label: string; 14 | jobGroup: string; 15 | measurand: string; 16 | page: string; 17 | data: number[]; 18 | median: number; 19 | 20 | constructor(dto: DistributionDTO) { 21 | this.identifier = dto.identifier; 22 | this.label = dto.label; 23 | this.jobGroup = dto.jobGroup; 24 | this.measurand = dto.measurand; 25 | this.page = dto.page; 26 | this.data = dto.data; 27 | this.median = dto.median; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /frontend/src/app/modules/distribution/services/violinchart-data.service.spec.ts: -------------------------------------------------------------------------------- 1 | import {TestBed} from '@angular/core/testing'; 2 | import {HttpClientTestingModule} from '@angular/common/http/testing'; 3 | import {ViolinchartDataService} from './violinchart-data.service'; 4 | 5 | describe('ViolinchartDataService', () => { 6 | beforeEach(() => 7 | TestBed.configureTestingModule({ 8 | providers: [ 9 | ViolinchartDataService, 10 | ], 11 | imports: [ 12 | HttpClientTestingModule 13 | ] 14 | })); 15 | 16 | it('should be created', () => { 17 | const service: ViolinchartDataService = TestBed.get(ViolinchartDataService); 18 | expect(service).toBeTruthy(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /frontend/src/app/modules/job-threshold/components/threshold-group/threshold-group.component.scss: -------------------------------------------------------------------------------- 1 | osm-threshold { 2 | display: block; 3 | margin-bottom: 20px; 4 | } 5 | 6 | .threshold-group { 7 | display: flex; 8 | justify-content: flex-start; 9 | flex-flow: row wrap; 10 | } 11 | 12 | .measured-event-name { 13 | flex: 0 1 20%; 14 | margin-right: 20px; 15 | } 16 | 17 | label.measured-event-name { 18 | font-size: 1em; 19 | font-weight: bold; 20 | word-break: break-all; 21 | margin-bottom: 20px; 22 | } 23 | 24 | .flex-column-right { 25 | flex-basis: 700px; 26 | flex-grow: 1; 27 | button { 28 | width: auto; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /frontend/src/app/modules/job-threshold/components/threshold-row/threshold-row.component.scss: -------------------------------------------------------------------------------- 1 | .threshold-row { 2 | display: flex; 3 | justify-content: flex-start; 4 | align-content: center; 5 | line-height: 2; 6 | 7 | > * { 8 | margin-right: 5px; 9 | } 10 | 11 | span { 12 | font-weight: bold; 13 | text-align: center; 14 | font-size: 1.15em; 15 | } 16 | } 17 | 18 | .input-group { 19 | max-width: 9.4em; 20 | margin-right: 5px; 21 | flex-shrink: 0; 22 | } 23 | -------------------------------------------------------------------------------- /frontend/src/app/modules/job-threshold/components/threshold/threshold.component.html: -------------------------------------------------------------------------------- 1 | 2 | 7 | 15 | -------------------------------------------------------------------------------- /frontend/src/app/modules/job-threshold/components/threshold/threshold.component.scss: -------------------------------------------------------------------------------- 1 | select { 2 | margin-bottom: 10px; 3 | width: auto; 4 | } 5 | -------------------------------------------------------------------------------- /frontend/src/app/modules/job-threshold/job-threshold.component.scss: -------------------------------------------------------------------------------- 1 | .message { 2 | color: grey; 3 | font-style: italic; 4 | } 5 | -------------------------------------------------------------------------------- /frontend/src/app/modules/job-threshold/models/measurand.model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by glastra on 27.06.18. 3 | */ 4 | import {Unit} from "./unit.model"; 5 | 6 | export type Measurand = { 7 | name: string; 8 | translationsKey: string; 9 | unit: Unit; 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/app/modules/job-threshold/models/measured-event.model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by glastra on 27.06.18. 3 | */ 4 | import {TestedPage} from "./tested-page.model"; 5 | export type MeasuredEvent = { 6 | id: number; 7 | name: string; 8 | testedPage: TestedPage; 9 | testedPageId: number; 10 | state: string; 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/app/modules/job-threshold/models/tested-page.model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by glastra on 27.06.18. 3 | */ 4 | export type TestedPage = { 5 | id: number; 6 | name: string; 7 | undefinedPage: boolean; 8 | } 9 | -------------------------------------------------------------------------------- /frontend/src/app/modules/job-threshold/models/threshold-for-job.model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by glastra on 27.06.18. 3 | */ 4 | import {MeasuredEvent} from './measured-event.model'; 5 | import {Threshold} from './threshold.model'; 6 | 7 | export type ThresholdGroup = { 8 | measuredEvent: MeasuredEvent; 9 | thresholds: Threshold[]; 10 | isNew?: boolean; 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/app/modules/job-threshold/models/threshold.model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by glastra on 27.06.18. 3 | */ 4 | 5 | import {MeasuredEvent} from './measured-event.model'; 6 | import {Measurand} from './measurand.model'; 7 | 8 | export type Threshold = { 9 | id?: number; 10 | lowerBoundary: number; 11 | measurand: Measurand; 12 | measuredEvent: MeasuredEvent; 13 | upperBoundary: number; 14 | isNew?: boolean; 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/app/modules/job-threshold/models/unit.model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by glastra on 27.06.18. 3 | */ 4 | export type Unit = { 5 | enumType: string; 6 | name: string; 7 | } 8 | -------------------------------------------------------------------------------- /frontend/src/app/modules/landing/components/continue-setup/continue-setup.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |

{{ "frontend.de.iteratec.osm.landing.incomplete-setup-title" | translate}}

5 | 7 | 8 | {{ "frontend.de.iteratec.osm.landing.continue-setup" | translate }} 9 | 10 |
11 |
12 | -------------------------------------------------------------------------------- /frontend/src/app/modules/landing/components/continue-setup/continue-setup.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../../styles/variables"; 2 | 3 | .logo { 4 | display: block; 5 | width: 200px; 6 | margin: 0 auto $default-padding auto; 7 | } 8 | 9 | main { 10 | display: flex; 11 | width: 100%; 12 | justify-content: center; 13 | } 14 | -------------------------------------------------------------------------------- /frontend/src/app/modules/landing/components/continue-setup/continue-setup.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'osm-continue-setup', 5 | templateUrl: './continue-setup.component.html', 6 | styleUrls: ['./continue-setup.component.scss'] 7 | }) 8 | export class ContinueSetupComponent { 9 | 10 | constructor() { 11 | } 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/app/modules/landing/landing.module.spec.ts: -------------------------------------------------------------------------------- 1 | import { LandingModule } from './landing.module'; 2 | 3 | describe('LandingModule', () => { 4 | let landingModule: LandingModule; 5 | 6 | beforeEach(() => { 7 | landingModule = new LandingModule(); 8 | }); 9 | 10 | it('should create an instance', () => { 11 | expect(landingModule).toBeTruthy(); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /frontend/src/app/modules/landing/landing.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {LandingComponent} from './landing.component'; 3 | import {RouterModule} from "@angular/router"; 4 | import {SharedModule} from "../shared/shared.module"; 5 | import {ContinueSetupComponent} from './components/continue-setup/continue-setup.component'; 6 | 7 | @NgModule({ 8 | imports: [ 9 | RouterModule.forChild([ 10 | {path: '', component: LandingComponent}, 11 | {path: 'index', component: LandingComponent}, 12 | {path: 'continueSetup', component: ContinueSetupComponent} 13 | ]), 14 | SharedModule 15 | ], 16 | declarations: [LandingComponent, ContinueSetupComponent], 17 | }) 18 | export class LandingModule { 19 | } 20 | -------------------------------------------------------------------------------- /frontend/src/app/modules/landing/models/application-with-csi.model.ts: -------------------------------------------------------------------------------- 1 | import {Application} from "../../../models/application.model"; 2 | import {Csi} from "../../../models/csi.model"; 3 | import {ApplicationCsi} from "../../../models/application-csi.model"; 4 | 5 | export class ApplicationWithCsi extends Application { 6 | recentCsi: Csi; 7 | csiIsLoading: boolean; 8 | 9 | constructor(application: Application, applicationCsi: ApplicationCsi, isLoading: boolean) { 10 | super(application); 11 | const recentCsi = applicationCsi ? applicationCsi.recentCsi() : null; 12 | this.recentCsi = new Csi(recentCsi || {}); 13 | this.csiIsLoading = isLoading; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/app/modules/landing/models/failing-jobs.model.ts: -------------------------------------------------------------------------------- 1 | export interface FailingJobDTO { 2 | job_id: number; 3 | percentageFailLast5: number; 4 | location: string; 5 | application: string; 6 | script: string; 7 | browser: string; 8 | } 9 | 10 | export class FailingJob implements FailingJobDTO { 11 | application: string; 12 | job_id: number; 13 | percentageFailLast5: number; 14 | location: string; 15 | script: string; 16 | browser: string; 17 | 18 | constructor(dto: FailingJobDTO) { 19 | this.job_id = dto.job_id; 20 | this.percentageFailLast5 = dto.percentageFailLast5; 21 | this.location = dto.location; 22 | this.application = dto.application; 23 | this.script = dto.script; 24 | this.browser = dto.browser; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /frontend/src/app/modules/metric-finder/components/comparable-filmstrips/comparable-filmstrips.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 6 | 7 | 8 |
9 |
10 | -------------------------------------------------------------------------------- /frontend/src/app/modules/metric-finder/components/comparable-filmstrips/comparable-filmstrips.component.scss: -------------------------------------------------------------------------------- 1 | .filmstrips { 2 | overflow-x: auto; 3 | background: black; 4 | border-radius: 4px; 5 | } 6 | 7 | .filmstrips-wrapper { 8 | position: relative; 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/app/modules/metric-finder/components/line-chart/line-chart.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 | -------------------------------------------------------------------------------- /frontend/src/app/modules/metric-finder/components/line-chart/line-chart.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LineChartComponent } from './line-chart.component'; 4 | 5 | describe('LineChartComponent', () => { 6 | let component: LineChartComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LineChartComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LineChartComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/modules/metric-finder/components/metric-selection/metric-selection.component.html: -------------------------------------------------------------------------------- 1 |
2 | 7 |
8 | -------------------------------------------------------------------------------- /frontend/src/app/modules/metric-finder/components/metric-selection/metric-selection.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../../styles/colors"; 2 | 3 | .tag-list { 4 | display: flex; 5 | flex-wrap: wrap; 6 | 7 | .btn { 8 | margin: 0 .5rem 0.5rem 0; 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/app/modules/metric-finder/metric-finder.component.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /frontend/src/app/modules/metric-finder/metric-finder.component.scss: -------------------------------------------------------------------------------- 1 | 2 | osm-line-chart, osm-comparable-filmstrips { 3 | display: block; 4 | margin-bottom: 20px; 5 | } 6 | -------------------------------------------------------------------------------- /frontend/src/app/modules/metric-finder/models/filmstrip-view.model.ts: -------------------------------------------------------------------------------- 1 | 2 | export interface Timing { 3 | metric: string; 4 | time: number; 5 | } 6 | 7 | export interface FilmstripViewThumbnail { 8 | time: number; 9 | imageUrl: string; 10 | hasChange: boolean; 11 | isHighlighted: boolean; 12 | isOffset: boolean; 13 | timings: Timing[]; 14 | } 15 | 16 | export declare type FilmstripView = FilmstripViewThumbnail[]; 17 | -------------------------------------------------------------------------------- /frontend/src/app/modules/metric-finder/models/thumbnail.model.ts: -------------------------------------------------------------------------------- 1 | export interface ThumbnailDto { 2 | time: number; 3 | image: string; 4 | } 5 | 6 | export class Thumbnail { 7 | public time: number; 8 | public imageUrl: string; 9 | 10 | constructor(time: number, imageUrl: string) { 11 | this.time = time; 12 | this.imageUrl = imageUrl; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/app/modules/metric-finder/models/wptResult-dto.model.ts: -------------------------------------------------------------------------------- 1 | import {ThumbnailDto} from './thumbnail.model'; 2 | 3 | export interface WptResultDTO { 4 | data: { 5 | runs: { 6 | [runNumber: number]: { 7 | firstView: { 8 | steps: { 9 | videoFrames: ThumbnailDto[] 10 | }[] 11 | } 12 | } 13 | } 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/app/modules/metric-finder/services/filmstrip.service.mock.ts: -------------------------------------------------------------------------------- 1 | import {BehaviorSubject} from 'rxjs'; 2 | import {Thumbnail} from '../models/thumbnail.model'; 3 | import {TestResult} from '../models/test-result.model'; 4 | 5 | export class FilmstripServiceMock { 6 | 7 | filmStripData$ = new BehaviorSubject<{[resultId: string]: Thumbnail[]}>({}); 8 | 9 | loadFilmstripIfNecessary(result: TestResult): void {} 10 | 11 | loadFilmstrip(result: TestResult): void { } 12 | 13 | getThumbnailTime(time: number): number { return 0; } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/app/modules/metric-finder/services/metric-finder.service.mock.ts: -------------------------------------------------------------------------------- 1 | import {BehaviorSubject} from 'rxjs'; 2 | import {TestResult} from '../models/test-result.model'; 3 | 4 | export class MetricFinderServiceMock { 5 | public testResults$ = new BehaviorSubject([]); 6 | 7 | loadTestData(): void { 8 | 9 | } 10 | 11 | public loadData(from: Date, to: Date, application: number, page: number, browser: number): void { 12 | 13 | } 14 | 15 | 16 | getMetricName(metric: string): string { 17 | return 'name:' + metric; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frontend/src/app/modules/page-comparison/models/job-group-to-page-mapping.model.ts: -------------------------------------------------------------------------------- 1 | import {PageDto} from "./page.model"; 2 | 3 | export interface JobGroupToPagesMappingDto { 4 | id: number; 5 | name: string; 6 | pages: PageDto[]; 7 | } 8 | -------------------------------------------------------------------------------- /frontend/src/app/modules/page-comparison/models/page-comparison-selection.model.ts: -------------------------------------------------------------------------------- 1 | export interface PageComparisonSelectionDto { 2 | firstJobGroupId: number; 3 | firstPageId: number; 4 | secondJobGroupId: number; 5 | secondPageId: number; 6 | } 7 | -------------------------------------------------------------------------------- /frontend/src/app/modules/page-comparison/models/page.model.ts: -------------------------------------------------------------------------------- 1 | export interface PageDto { 2 | name: string; 3 | id: number; 4 | } 5 | -------------------------------------------------------------------------------- /frontend/src/app/modules/page-comparison/services/job-group.service.spec.ts: -------------------------------------------------------------------------------- 1 | import {inject, TestBed} from '@angular/core/testing'; 2 | 3 | import {JobGroupService} from './job-group.service'; 4 | import {HttpClientTestingModule} from '@angular/common/http/testing'; 5 | 6 | describe('JobGroupService', () => { 7 | beforeEach(() => { 8 | TestBed.configureTestingModule({ 9 | providers: [ 10 | JobGroupService 11 | ], 12 | imports: [ 13 | HttpClientTestingModule 14 | ] 15 | }); 16 | }); 17 | 18 | it('should be created', inject([JobGroupService], (service: JobGroupService) => { 19 | expect(service).toBeTruthy(); 20 | })); 21 | }); 22 | -------------------------------------------------------------------------------- /frontend/src/app/modules/page-comparison/services/job-group.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {Observable} from "rxjs/index"; 3 | import {HttpClient} from "@angular/common/http"; 4 | import {JobGroupToPagesMappingDto} from "../models/job-group-to-page-mapping.model"; 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class JobGroupService { 10 | 11 | constructor(private http: HttpClient) { 12 | } 13 | 14 | getJobGroupToPagesMapDto(from: string, to: string): Observable { 15 | return this.http.get('/jobGroup/getJobGroupsWithPages', { 16 | params: { 17 | from: from, 18 | to: to 19 | } 20 | }); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /frontend/src/app/modules/queue-dashboard/components/location-info-list/location-info-list.component.scss: -------------------------------------------------------------------------------- 1 | .one-indent { 2 | padding: 2px 1em 2px 1em; 3 | } 4 | 5 | .two-indent { 6 | padding: 2px 1em 2px 2em; 7 | } 8 | 9 | .chevron-large { 10 | font-size: large; 11 | cursor: pointer; 12 | } 13 | 14 | .new-col-sec { 15 | border-left: 2px #ccc solid; 16 | } 17 | 18 | .job-row { 19 | display: table-row; 20 | } 21 | -------------------------------------------------------------------------------- /frontend/src/app/modules/queue-dashboard/models/LocationInfoDTO.ts: -------------------------------------------------------------------------------- 1 | export interface LocationInfoDTO { 2 | id: string 3 | lastHealthCheckDate: string 4 | label: string 5 | agents: number 6 | jobs: number 7 | 8 | eventResultsLastHour: number 9 | jobResultsLastHour: number 10 | errorsLastHour: number 11 | 12 | jobsNextHour: number 13 | eventsNextHour: number 14 | 15 | executingJobs: Array> 16 | pendingJobs: number 17 | runningJobs: number 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/app/modules/queue-dashboard/models/WptServerDTO.ts: -------------------------------------------------------------------------------- 1 | export interface WptServerDTO { 2 | label: string 3 | proxyIdentifier: string 4 | 5 | dateCreated: any 6 | lastUpdate: any 7 | id: number 8 | 9 | baseUrl: string 10 | active: boolean 11 | description: string 12 | contactPersonName: string 13 | contactPersonEmail: string 14 | 15 | apiKey: String 16 | } 17 | -------------------------------------------------------------------------------- /frontend/src/app/modules/queue-dashboard/queue-dashboard.component.scss: -------------------------------------------------------------------------------- 1 | .chevron-large { 2 | color: #606060; 3 | font-size: xx-large; 4 | float: right; 5 | margin-right: 0.5em; 6 | margin-bottom: 0.5em; 7 | cursor: pointer; 8 | display: none; 9 | } 10 | 11 | h2 { 12 | display: inline-block; 13 | } 14 | -------------------------------------------------------------------------------- /frontend/src/app/modules/result-selection/components/application/application.component.scss: -------------------------------------------------------------------------------- 1 | .tag-button-group { 2 | margin-top: 10px; 3 | } 4 | 5 | .tag-buttons { 6 | margin-right: 2px; 7 | margin-bottom: 2px; 8 | } 9 | -------------------------------------------------------------------------------- /frontend/src/app/modules/result-selection/components/measurands/measurand-select/measurand-select.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/frontend/src/app/modules/result-selection/components/measurands/measurand-select/measurand-select.component.scss -------------------------------------------------------------------------------- /frontend/src/app/modules/result-selection/components/measurands/measurands.component.scss: -------------------------------------------------------------------------------- 1 | .remove-measurand { 2 | text-align: left; 3 | padding-left: 0; 4 | padding-top: 7px; 5 | margin-bottom: 0; 6 | cursor: pointer; 7 | } 8 | 9 | .measurand-card-content { 10 | margin-top: 20px; 11 | margin-bottom: 20px; 12 | } 13 | 14 | #add-measurand-button { 15 | overflow: hidden; 16 | text-overflow: ellipsis; 17 | } 18 | -------------------------------------------------------------------------------- /frontend/src/app/modules/result-selection/components/page-location-connectivity/page-location-connectivity.component.scss: -------------------------------------------------------------------------------- 1 | .result-selection-tabs > li { 2 | cursor: pointer; 3 | } 4 | -------------------------------------------------------------------------------- /frontend/src/app/modules/result-selection/components/page-location-connectivity/selection-data/selection-data.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/frontend/src/app/modules/result-selection/components/page-location-connectivity/selection-data/selection-data.component.scss -------------------------------------------------------------------------------- /frontend/src/app/modules/result-selection/components/reset/reset.component.html: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /frontend/src/app/modules/result-selection/components/reset/reset.component.scss: -------------------------------------------------------------------------------- 1 | .reset-result-selection { 2 | float: right; 3 | } 4 | 5 | .btn-sm { 6 | padding: 5px 10px; 7 | font-size: 12px; 8 | line-height: 1.5; 9 | border-radius: 3px; 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/app/modules/result-selection/components/submit/submit.component.scss: -------------------------------------------------------------------------------- 1 | .get-barchart-data-warnings { 2 | font-weight: bold; 3 | padding: 7px 15px; 4 | margin: 0 5px 0 0; 5 | border-radius: 4px; 6 | float: left; 7 | } 8 | -------------------------------------------------------------------------------- /frontend/src/app/modules/result-selection/components/time-frame/time-frame-in-seconds.enum.ts: -------------------------------------------------------------------------------- 1 | export enum TIME_FRAME_IN_SECONDS { 2 | MANUAL_SELECTION = -1, 3 | ONE_HOUR = 3600, 4 | TWELVE_HOURS = 43200, 5 | ONE_DAY = 86400, 6 | THREE_DAYS = 259200, 7 | ONE_WEEK = 604800, 8 | TWO_WEEKS = 1209600, 9 | FOUR_WEEKS = 2419200 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/app/modules/result-selection/components/time-frame/time-frame.component.scss: -------------------------------------------------------------------------------- 1 | .remove-comparative-time-frame { 2 | text-align: left; 3 | padding-left: 0; 4 | padding-top: 7px; 5 | margin-bottom: 0; 6 | cursor: pointer; 7 | } 8 | 9 | .owl-dt-container { 10 | font-size: inherit; 11 | } 12 | 13 | .owl-dt-container-buttons, .owl-dt-container-info { 14 | display: none; 15 | } 16 | 17 | .owl-dt-timer-divider { 18 | font-size: 12px; 19 | } 20 | 21 | .time-frame-label { 22 | text-align: right; 23 | } 24 | 25 | #show-comparative-button { 26 | overflow: hidden; 27 | text-overflow: ellipsis; 28 | } 29 | -------------------------------------------------------------------------------- /frontend/src/app/modules/result-selection/models/chart-switch-menu-entry.model.ts: -------------------------------------------------------------------------------- 1 | export class ChartSwitchMenuEntry { 2 | baseUrl: string; 3 | label: string; 4 | icon: string; 5 | devUrl?: string; 6 | } 7 | -------------------------------------------------------------------------------- /frontend/src/app/modules/result-selection/result-selection.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /frontend/src/app/modules/result-selection/result-selection.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/frontend/src/app/modules/result-selection/result-selection.component.scss -------------------------------------------------------------------------------- /frontend/src/app/modules/result-selection/result-selection.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'osm-result-selection', 5 | templateUrl: './result-selection.component.html', 6 | styleUrls: ['./result-selection.component.scss'] 7 | }) 8 | export class ResultSelectionComponent { 9 | 10 | constructor() { } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /frontend/src/app/modules/result-selection/services/result-selection.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { ResultSelectionService } from './result-selection.service'; 4 | import {HttpClientTestingModule} from "@angular/common/http/testing"; 5 | import {ResultSelectionStore} from "./result-selection.store"; 6 | 7 | describe('ResultSelectionStore', () => { 8 | beforeEach(() => TestBed.configureTestingModule({ 9 | providers: [ 10 | ResultSelectionService, 11 | ResultSelectionStore 12 | ], 13 | imports: [ 14 | HttpClientTestingModule 15 | ] 16 | })); 17 | 18 | it('should be created', () => { 19 | const service: ResultSelectionService = TestBed.get(ResultSelectionService); 20 | expect(service).toBeTruthy(); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /frontend/src/app/modules/shared/components/chart-switch-menu/chart-switch-menu.component.html: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | {{ chart.label | translate }} 5 | 6 | 7 | 8 | {{ chart.label | translate }} {{ router.url.includes('Dev/') ? '(Dev)' : '' }} 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |

18 | -------------------------------------------------------------------------------- /frontend/src/app/modules/shared/components/chart-switch-menu/chart-switch-menu.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/frontend/src/app/modules/shared/components/chart-switch-menu/chart-switch-menu.component.scss -------------------------------------------------------------------------------- /frontend/src/app/modules/shared/components/csi-value/csi-value-base.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 | 7 |
8 |
9 | -------------------------------------------------------------------------------- /frontend/src/app/modules/shared/components/csi-value/csi-value-big/csi-value-big.component.html: -------------------------------------------------------------------------------- 1 | 4 | {{this.formattedCsiValue}} 5 | {{this.description}} 6 | 7 | -------------------------------------------------------------------------------- /frontend/src/app/modules/shared/components/csi-value/csi-value-big/csi-value-big.component.scss: -------------------------------------------------------------------------------- 1 | .csi-value-text { 2 | font-size: 34px; 3 | 4 | &.loading { 5 | font-size: 24px; 6 | } 7 | } 8 | 9 | .csi-value-description { 10 | font-size: 14px; 11 | margin-top: 8px; 12 | } 13 | -------------------------------------------------------------------------------- /frontend/src/app/modules/shared/components/csi-value/csi-value-medium/csi-value-medium.component.html: -------------------------------------------------------------------------------- 1 | 4 | {{this.formattedCsiValue}} 5 | CSI 6 | 7 | -------------------------------------------------------------------------------- /frontend/src/app/modules/shared/components/csi-value/csi-value-medium/csi-value-medium.component.scss: -------------------------------------------------------------------------------- 1 | .csi-value-text { 2 | font-size: 18px; 3 | 4 | &.loading { 5 | font-size: 10px; 6 | } 7 | } 8 | 9 | .csi-value-description { 10 | font-size: 12px; 11 | margin-top: 4px; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /frontend/src/app/modules/shared/components/csi-value/csi-value-small/csi-value-small.component.html: -------------------------------------------------------------------------------- 1 | 4 | {{this.formattedCsiValue}} 5 | 6 | -------------------------------------------------------------------------------- /frontend/src/app/modules/shared/components/csi-value/csi-value-small/csi-value-small.component.scss: -------------------------------------------------------------------------------- 1 | .csi-value-small { 2 | font-size: 10px; 3 | } 4 | -------------------------------------------------------------------------------- /frontend/src/app/modules/shared/components/empty-state/empty-state.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
{{ messageKey | translate }}
4 |
5 | -------------------------------------------------------------------------------- /frontend/src/app/modules/shared/components/empty-state/empty-state.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../../styles/variables"; 2 | @import "../../../../../styles/colors"; 3 | 4 | figure.empty-state { 5 | margin-bottom: $default-padding; 6 | padding: $default-padding; 7 | display: flex; 8 | flex-direction: column; 9 | align-items: center; 10 | 11 | img { 12 | max-width: 250px; 13 | } 14 | figcaption { 15 | text-align: center; 16 | color: $color-text-light; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/app/modules/shared/components/empty-state/empty-state.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'osm-empty-state', 5 | templateUrl: './empty-state.component.html', 6 | styleUrls: ['./empty-state.component.scss'] 7 | }) 8 | export class EmptyStateComponent { 9 | 10 | @Input() 11 | messageKey: string; 12 | 13 | @Input() 14 | image: string; 15 | 16 | constructor() { 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/app/modules/shared/components/spinner/spinner.component.html: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /frontend/src/app/modules/shared/components/spinner/spinner.component.scss: -------------------------------------------------------------------------------- 1 | @keyframes spinner-line-fade-more { 2 | 0%, 100% { 3 | opacity: 0; /* minimum opacity */ 4 | } 5 | 1% { 6 | opacity: 1; 7 | } 8 | } 9 | 10 | @keyframes spinner-line-fade-quick { 11 | 0%, 39%, 100% { 12 | opacity: 0.25; /* minimum opacity */ 13 | } 14 | 40% { 15 | opacity: 1; 16 | } 17 | } 18 | 19 | @keyframes spinner-line-fade-default { 20 | 0%, 100% { 21 | opacity: 0.22; /* minimum opacity */ 22 | } 23 | 1% { 24 | opacity: 1; 25 | } 26 | } 27 | 28 | .spinner-container { 29 | position: absolute; 30 | min-width: 100%; 31 | min-height: 100%; 32 | background: white; 33 | opacity: 0.5; 34 | z-index: 10; 35 | top: 0; 36 | left: 0; 37 | } 38 | -------------------------------------------------------------------------------- /frontend/src/app/modules/shared/components/spinner/spinner.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { SpinnerComponent } from './spinner.component'; 3 | 4 | describe('SpinnerComponent', () => { 5 | let component: SpinnerComponent; 6 | let fixture: ComponentFixture; 7 | 8 | beforeEach(async(() => { 9 | TestBed.configureTestingModule({ 10 | declarations: [ SpinnerComponent ] 11 | }) 12 | .compileComponents(); 13 | })); 14 | 15 | beforeEach(() => { 16 | fixture = TestBed.createComponent(SpinnerComponent); 17 | component = fixture.componentInstance; 18 | fixture.detectChanges(); 19 | }); 20 | 21 | it('should create', () => { 22 | expect(component).toBeTruthy(); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /frontend/src/app/modules/shared/services/spinner.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import {BehaviorSubject} from "rxjs"; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class SpinnerService { 8 | 9 | activeSpinner$ = new BehaviorSubject>(new Set()); 10 | 11 | constructor() { } 12 | 13 | showSpinner(spinnerId: string): void { 14 | let activeSpinner: Set = this.activeSpinner$.getValue(); 15 | activeSpinner.add(spinnerId); 16 | this.activeSpinner$.next(activeSpinner); 17 | } 18 | 19 | hideSpinner(spinnerId: string): void { 20 | let activeSpinner: Set = this.activeSpinner$.getValue(); 21 | activeSpinner.delete(spinnerId); 22 | this.activeSpinner$.next(activeSpinner); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /frontend/src/app/modules/shared/shared.module.spec.ts: -------------------------------------------------------------------------------- 1 | import { SharedModule } from './shared.module'; 2 | 3 | describe('SharedModule', () => { 4 | let sharedModule: SharedModule; 5 | 6 | beforeEach(() => { 7 | sharedModule = new SharedModule(); 8 | }); 9 | 10 | it('should create an instance', () => { 11 | expect(sharedModule).toBeTruthy(); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /frontend/src/app/modules/time-series/models/context-menu-position.model.ts: -------------------------------------------------------------------------------- 1 | import {TimeSeriesPoint} from './time-series-point.model'; 2 | 3 | export default class ContextMenuPosition { 4 | // if divider is set on true, the other fields are ignored 5 | divider ? = false; 6 | 7 | title?: string; 8 | icon?: string; 9 | visible?: (d: TimeSeriesPoint, i: number, elem) => boolean; 10 | action?: (d: TimeSeriesPoint, i: number, elem) => void; 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/app/modules/time-series/models/event-result-data.model.ts: -------------------------------------------------------------------------------- 1 | import {EventResultSeriesDTO} from './event-result-series.model'; 2 | import {SummaryLabel} from './summary-label.model'; 3 | 4 | export interface EventResultDataDTO { 5 | measurandGroups: { [key: string]: string }; 6 | series: EventResultSeriesDTO[]; 7 | summaryLabels: SummaryLabel[]; 8 | numberOfTimeSeries: number; 9 | } 10 | 11 | export class EventResultData implements EventResultDataDTO { 12 | measurandGroups: { [key: string]: string }; 13 | series: EventResultSeriesDTO[]; 14 | summaryLabels: SummaryLabel[]; 15 | numberOfTimeSeries: number; 16 | 17 | constructor() { 18 | this.measurandGroups = {}; 19 | this.series = []; 20 | this.summaryLabels = []; 21 | this.numberOfTimeSeries = 0; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /frontend/src/app/modules/time-series/models/event-result-point.model.ts: -------------------------------------------------------------------------------- 1 | import {WptInfo} from './wpt-info.model'; 2 | 3 | export interface EventResultPointDTO { 4 | date: Date; 5 | value: number; 6 | agent: string; 7 | wptInfo: WptInfo; 8 | } 9 | 10 | export class EventResultPoint implements EventResultPointDTO { 11 | date: Date; 12 | value: number; 13 | agent: string; 14 | wptInfo: WptInfo; 15 | 16 | constructor(dto: EventResultPointDTO) { 17 | this.date = dto.date; 18 | this.value = dto.value; 19 | this.agent = dto.agent; 20 | this.wptInfo = dto.wptInfo; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /frontend/src/app/modules/time-series/models/event-result-series.model.ts: -------------------------------------------------------------------------------- 1 | import {EventResultPointDTO} from './event-result-point.model'; 2 | 3 | export interface EventResultSeriesDTO { 4 | identifier: string; 5 | jobGroup: string; 6 | measuredEvent: string; 7 | data: EventResultPointDTO[]; 8 | } 9 | 10 | export class EventResultSeries implements EventResultSeriesDTO { 11 | identifier: string; 12 | jobGroup: string; 13 | measuredEvent: string; 14 | data: EventResultPointDTO[]; 15 | 16 | constructor(dto: EventResultSeriesDTO) { 17 | this.identifier = dto.identifier; 18 | this.jobGroup = dto.jobGroup; 19 | this.measuredEvent = dto.measuredEvent; 20 | this.data = dto.data; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /frontend/src/app/modules/time-series/models/summary-label.model.ts: -------------------------------------------------------------------------------- 1 | export interface SummaryLabel { 2 | key: string; 3 | label: string; 4 | } 5 | -------------------------------------------------------------------------------- /frontend/src/app/modules/time-series/models/time-series-point.model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Representation of one point on the y-axis (value) with additional informations. 3 | */ 4 | import {WptInfo} from './wpt-info.model'; 5 | 6 | export class TimeSeriesPoint { 7 | date: Date; 8 | value: number; 9 | agent: string; 10 | tooltipText: string; 11 | wptInfo: WptInfo; 12 | 13 | constructor() { 14 | } 15 | 16 | public equals(other: TimeSeriesPoint) { 17 | return other && this.date.getTime() === other.date.getTime() && this.tooltipText === other.tooltipText && this.value === other.value; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frontend/src/app/modules/time-series/models/time-series.model.ts: -------------------------------------------------------------------------------- 1 | import {TimeSeriesPoint} from './time-series-point.model'; 2 | 3 | /** 4 | * Representation of on point on the x-axis (key) with all data for the y-axis (values). 5 | */ 6 | export class TimeSeries { 7 | key: string; 8 | values: TimeSeriesPoint[]; 9 | 10 | constructor() { 11 | this.key = ''; 12 | this.values = [new TimeSeriesPoint()]; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/app/modules/time-series/models/wpt-info.model.ts: -------------------------------------------------------------------------------- 1 | export class WptInfo { 2 | baseUrl: string; 3 | testId: string; 4 | runNumber: number; 5 | indexInJourney: number; 6 | } 7 | -------------------------------------------------------------------------------- /frontend/src/app/not-found.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'osm-not-found', 5 | template: 'Not Found', 6 | } 7 | ) 8 | export class NotFoundComponent { 9 | constructor() { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/app/services/osm-lang.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from "@angular/core"; 2 | import {GrailsBridgeService} from "./grails-bridge.service"; 3 | 4 | @Injectable() 5 | export class OsmLangService { 6 | 7 | constructor(private grailsBridgeService: GrailsBridgeService) { 8 | } 9 | 10 | getOsmLang(): string { 11 | if (this.grailsBridgeService.globalOsmNamespace && 12 | this.grailsBridgeService.globalOsmNamespace.i18n) { 13 | return this.grailsBridgeService.globalOsmNamespace.i18n.lang; 14 | } else { 15 | return undefined; 16 | } 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frontend/src/app/services/performance-aspect.service.spec.ts: -------------------------------------------------------------------------------- 1 | import {TestBed} from '@angular/core/testing'; 2 | 3 | import {PerformanceAspectService} from './performance-aspect.service'; 4 | import {HttpClientTestingModule} from "@angular/common/http/testing"; 5 | 6 | describe('PerformanceAspectService', () => { 7 | beforeEach(() => TestBed.configureTestingModule({ 8 | imports: [ 9 | HttpClientTestingModule 10 | ] 11 | })); 12 | 13 | it('should be created', () => { 14 | const service: PerformanceAspectService = TestBed.get(PerformanceAspectService); 15 | expect(service).toBeTruthy(); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /frontend/src/app/testing/ngx-translate-mocks.ts: -------------------------------------------------------------------------------- 1 | import {TranslateLoader} from '@ngx-translate/core'; 2 | import {Observable, of} from 'rxjs'; 3 | 4 | export class TranslateTestLoader extends TranslateLoader { 5 | getTranslation(lang: string): Observable { 6 | return of({}); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /frontend/src/app/utils/date.util.ts: -------------------------------------------------------------------------------- 1 | 2 | export function parseDate(datelike: string | Date): Date { 3 | if (datelike instanceof Date) { 4 | return new Date(datelike.getTime()); 5 | } else { 6 | return new Date(datelike); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/frontend/src/assets/.gitkeep -------------------------------------------------------------------------------- /frontend/src/browserslist: -------------------------------------------------------------------------------- 1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | # For IE 9-11 support, please uncomment the last line of the file and adjust as needed 5 | > 0.5% 6 | last 2 versions 7 | Firefox ESR 8 | not dead 9 | # IE 9-11 -------------------------------------------------------------------------------- /frontend/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /frontend/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build ---prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * In development mode, to ignore zone related error stack frames such as 11 | * `zone.run`, `zoneDelegate.invokeTask` for easier debugging, you can 12 | * import the following file, but please comment it out in production mode 13 | * because it will have performance impact when throw error 14 | */ 15 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 16 | -------------------------------------------------------------------------------- /frontend/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /frontend/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.log(err)); 13 | -------------------------------------------------------------------------------- /frontend/src/styles.scss: -------------------------------------------------------------------------------- 1 | @import "styles/layout"; 2 | @import "styles/fonts"; 3 | @import "styles/cards"; 4 | @import "styles/modals"; 5 | @import "~ng-pick-datetime/assets/style/picker.min.css"; 6 | @import "~@ng-select/ng-select/themes/default.theme.css"; 7 | -------------------------------------------------------------------------------- /frontend/src/styles/cards.scss: -------------------------------------------------------------------------------- 1 | @import "colors"; 2 | 3 | .card { 4 | background-color: $color-card-background; 5 | border-radius: 4px; 6 | padding: 20px; 7 | box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.17); 8 | margin: 0 20px 20px 0; 9 | 10 | &:last-of-type { 11 | margin: 0 0 20px 0; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /frontend/src/styles/colors.scss: -------------------------------------------------------------------------------- 1 | $color-text-normal: #000000; 2 | $color-text-medium: #333333; 3 | $color-text-light: #606060; 4 | $color-background: #ededed; 5 | $color-card-background: #ffffff; 6 | $color-contour-light: #d6d6d6; 7 | $color-contour-medium: #606060; 8 | $color-primary: #008cd2; 9 | $color-good: #00bd58; 10 | $color-good-light: #9DDEA9; 11 | $color-warning: #CF8116; 12 | $color-warning-light: #FDEDD9; 13 | $color-warning-percentage: #DC8F16; 14 | $color-error: #b70f0a; 15 | $color-error-light: #FCE0E0; 16 | $color-error-percentage: #DC0D00; 17 | -------------------------------------------------------------------------------- /frontend/src/styles/fonts.scss: -------------------------------------------------------------------------------- 1 | @import "colors"; 2 | 3 | h1 { 4 | font: { 5 | size: 24px; 6 | } 7 | color: $color-text-normal; 8 | margin: 0 0 20px 10px; 9 | } 10 | 11 | h2 { 12 | font: { 13 | size: 18px; 14 | weight: bold; 15 | } 16 | color: $color-text-normal; 17 | margin: 0 0 20px 0; 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/styles/layout.scss: -------------------------------------------------------------------------------- 1 | @import "colors"; 2 | 3 | .content { 4 | padding: 20px; 5 | } 6 | 7 | .good { 8 | color: $color-good; 9 | } 10 | 11 | .okay { 12 | color: $color-warning; 13 | } 14 | 15 | .bad { 16 | color: $color-error; 17 | } 18 | 19 | .neutral { 20 | color: $color-text-light; 21 | } 22 | -------------------------------------------------------------------------------- /frontend/src/styles/modals.scss: -------------------------------------------------------------------------------- 1 | $dialog-position-top: 10%; 2 | 3 | @import "~ngx-smart-modal/ngx-smart-modal"; 4 | 5 | #graphiteIntegrationModal { 6 | .nsm-dialog { 7 | max-width: 1200px; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/styles/variables.scss: -------------------------------------------------------------------------------- 1 | 2 | $default-padding: 20px; 3 | -------------------------------------------------------------------------------- /frontend/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /frontend/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "es2015", 6 | "types": [] 7 | }, 8 | "exclude": [ 9 | "src/test.ts", 10 | "**/*.spec.ts" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /frontend/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "module": "commonjs", 6 | "types": [ 7 | "jasmine", 8 | "node" 9 | ] 10 | }, 11 | "files": [ 12 | "test.ts", 13 | "polyfills.ts" 14 | ], 15 | "include": [ 16 | "**/*.spec.ts", 17 | "**/*.d.ts" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /frontend/src/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "osm", 8 | "camelCase" 9 | ], 10 | "component-selector": [ 11 | true, 12 | "element", 13 | "osm", 14 | "kebab-case" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "moduleResolution": "node", 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "target": "es5", 12 | "typeRoots": [ 13 | "node_modules/@types" 14 | ], 15 | "lib": [ 16 | "es2017", 17 | "dom" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | grailsVersion=3.3.6 2 | gradleWrapperVersion=4.8 3 | hibernateVersion=6.1.10.RELEASE -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Jun 17 14:03:33 CEST 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-all.zip 7 | -------------------------------------------------------------------------------- /grails-app/assets/images/OpenSpeedMonitor_Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/OpenSpeedMonitor_Icon.png -------------------------------------------------------------------------------- /grails-app/assets/images/WPT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/WPT.png -------------------------------------------------------------------------------- /grails-app/assets/images/api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/api.png -------------------------------------------------------------------------------- /grails-app/assets/images/csi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/csi.png -------------------------------------------------------------------------------- /grails-app/assets/images/exampleScript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/exampleScript.png -------------------------------------------------------------------------------- /grails-app/assets/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/favicon.ico -------------------------------------------------------------------------------- /grails-app/assets/images/flags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/flags.png -------------------------------------------------------------------------------- /grails-app/assets/images/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /grails-app/assets/images/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/glyphicons-halflings.png -------------------------------------------------------------------------------- /grails-app/assets/images/iteratec-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/iteratec-logo.png -------------------------------------------------------------------------------- /grails-app/assets/images/jobGroupSelection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/jobGroupSelection.png -------------------------------------------------------------------------------- /grails-app/assets/images/jobs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/jobs.png -------------------------------------------------------------------------------- /grails-app/assets/images/leftnav_btm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/leftnav_btm.png -------------------------------------------------------------------------------- /grails-app/assets/images/leftnav_midstretch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/leftnav_midstretch.png -------------------------------------------------------------------------------- /grails-app/assets/images/leftnav_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/leftnav_top.png -------------------------------------------------------------------------------- /grails-app/assets/images/loading_indicator.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/loading_indicator.gif -------------------------------------------------------------------------------- /grails-app/assets/images/menu-separator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/menu-separator.png -------------------------------------------------------------------------------- /grails-app/assets/images/results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/results.png -------------------------------------------------------------------------------- /grails-app/assets/images/skin/database_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/skin/database_add.png -------------------------------------------------------------------------------- /grails-app/assets/images/skin/database_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/skin/database_delete.png -------------------------------------------------------------------------------- /grails-app/assets/images/skin/database_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/skin/database_edit.png -------------------------------------------------------------------------------- /grails-app/assets/images/skin/database_save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/skin/database_save.png -------------------------------------------------------------------------------- /grails-app/assets/images/skin/database_table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/skin/database_table.png -------------------------------------------------------------------------------- /grails-app/assets/images/skin/exclamation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/skin/exclamation.png -------------------------------------------------------------------------------- /grails-app/assets/images/skin/house.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/skin/house.png -------------------------------------------------------------------------------- /grails-app/assets/images/skin/information.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/skin/information.png -------------------------------------------------------------------------------- /grails-app/assets/images/skin/shadow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/skin/shadow.jpg -------------------------------------------------------------------------------- /grails-app/assets/images/skin/sorted_asc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/skin/sorted_asc.gif -------------------------------------------------------------------------------- /grails-app/assets/images/skin/sorted_desc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/skin/sorted_desc.gif -------------------------------------------------------------------------------- /grails-app/assets/images/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/assets/images/spinner.gif -------------------------------------------------------------------------------- /grails-app/assets/javascripts/aggregation/aggregation.js: -------------------------------------------------------------------------------- 1 | //= require aggregationChart.js 2 | //= require aggregationGuiHandling.js 3 | //= require aggregationHistoryStateHandling.js 4 | //= require_self 5 | -------------------------------------------------------------------------------- /grails-app/assets/javascripts/chartComponents/common.js: -------------------------------------------------------------------------------- 1 | 2 | "use strict"; 3 | 4 | var OpenSpeedMonitor = OpenSpeedMonitor || {}; 5 | OpenSpeedMonitor.ChartComponents = OpenSpeedMonitor.ChartComponents || {}; 6 | 7 | OpenSpeedMonitor.ChartComponents.common = { 8 | transitionDuration: 500, 9 | barBand: 40, 10 | barGap: 5, 11 | ComponentMargin: 15 12 | }; 13 | -------------------------------------------------------------------------------- /grails-app/assets/javascripts/codemirror/codemirrorManifest.js: -------------------------------------------------------------------------------- 1 | //= require node_modules/codemirror/lib/codemirror.js 2 | //= require node_modules/codemirror/addon/hint/show-hint.js 3 | //= require hint/pts-hint.js 4 | //= require mode/pts.js 5 | //= require codemirror-usage.js 6 | //= require_self 7 | fireWindowEvent("CodeMirrorManifestArrived"); -------------------------------------------------------------------------------- /grails-app/assets/javascripts/eventresult/eventResult.js: -------------------------------------------------------------------------------- 1 | //= require listResult.js -------------------------------------------------------------------------------- /grails-app/assets/javascripts/eventresultdashboard/eventResultDashboard.js: -------------------------------------------------------------------------------- 1 | //= require iteratecChartRickshaw.js 2 | //= require showAll.js 3 | -------------------------------------------------------------------------------- /grails-app/assets/javascripts/iteratecChartRickshaw.js: -------------------------------------------------------------------------------- 1 | //= require node_modules/d3/d3.min.js 2 | //= require rickshaw/rickshaw_custom.js 3 | //= require rickshaw/rickshawChartCreation.js 4 | //= require rickshaw/html2canvas.js 5 | //= require rickshaw/html2canvas.svg.js 6 | //= require charts/chart-export.js 7 | //= require charts/chart-adjustment.js -------------------------------------------------------------------------------- /grails-app/assets/javascripts/job/jobList.js: -------------------------------------------------------------------------------- 1 | //= require list.js 2 | //= require jobListFilter.js 3 | //= require node_modules/sticky-table-headers/js/jquery.stickytableheaders.min.js -------------------------------------------------------------------------------- /grails-app/assets/javascripts/measurementSetup/measurementSetupWizard.js: -------------------------------------------------------------------------------- 1 | //= require _wizard.js 2 | //= require _createJobGroup.js 3 | //= require _createScript.js 4 | //= require _selectLocationAndConnectivity.js 5 | //= require _createJob.js 6 | -------------------------------------------------------------------------------- /grails-app/assets/javascripts/pageComparison/pageComparison.js: -------------------------------------------------------------------------------- 1 | //= require pageComparisonChart.js 2 | //= require pageComparisonChartData.js 3 | //= require pageComparisonGuiHandling.js 4 | //= require pageComparisonHistoryStateHandling.js 5 | -------------------------------------------------------------------------------- /grails-app/assets/javascripts/prettycron/prettycronManifest.js: -------------------------------------------------------------------------------- 1 | //= require prettycron/cron-expressions.js 2 | //= require node_modules/later/later.min.js 3 | //= require node_modules/moment/min/moment.min.js 4 | //= require node_modules/prettycron/prettycron.js 5 | -------------------------------------------------------------------------------- /grails-app/assets/javascripts/timeago/futureOnlyTimeago.js: -------------------------------------------------------------------------------- 1 | //= require jquery.timeago.js 2 | //= require future-only-timeago.js 3 | -------------------------------------------------------------------------------- /grails-app/assets/javascripts/timeago/jquery.timeago.de.js: -------------------------------------------------------------------------------- 1 | // German 2 | jQuery.timeago.settings.strings = { 3 | prefixAgo: "vor", 4 | prefixFromNow: "in", 5 | suffixAgo: "", 6 | suffixFromNow: "", 7 | seconds: "wenigen Sekunden", 8 | minute: "etwa einer Minute", 9 | minutes: "%d Minuten", 10 | hour: "etwa einer Stunde", 11 | hours: "%d Stunden", 12 | day: "etwa einem Tag", 13 | days: "%d Tagen", 14 | month: "etwa einem Monat", 15 | months: "%d Monaten", 16 | year: "etwa einem Jahr", 17 | years: "%d Jahren" 18 | }; -------------------------------------------------------------------------------- /grails-app/assets/javascripts/timeago/timeagoDe.js: -------------------------------------------------------------------------------- 1 | //= require timeago/jquery.timeago.de.js -------------------------------------------------------------------------------- /grails-app/assets/stylesheets/_resultSelection/selectBarchartMeasurings.css: -------------------------------------------------------------------------------- 1 | .measurandSeries { 2 | position: relative; 3 | padding-top: 20px; 4 | margin-bottom: 20px; 5 | } 6 | 7 | .measurandSeries .row{ 8 | margin-bottom: 15px; 9 | } 10 | 11 | .removeMeasurandSeriesContainer { 12 | position: absolute; 13 | right: 0px; 14 | top: 0px; 15 | } 16 | 17 | .removeMeasurandSeriesButton { 18 | color: #cccccc; 19 | } 20 | 21 | .control-label.removeAddMeasurands { 22 | text-align: left; 23 | padding-left: 0; 24 | color: black !important; 25 | } -------------------------------------------------------------------------------- /grails-app/assets/stylesheets/application.less: -------------------------------------------------------------------------------- 1 | /* 2 | *= require fontawesome 3 | *= require_tree node_modules/jquery-contextmenu/dist 4 | *= require_tree node_modules/bootstrap-colorpicker/dist/css 5 | *= require node_modules/air-datepicker/dist/css/datepicker.min.css 6 | *= require bootstrap-chosen-custom 7 | *= require flags 8 | *= require openspeedmonitor 9 | */ 10 | 11 | 12 | -------------------------------------------------------------------------------- /grails-app/assets/stylesheets/bootstrap-chosen-custom.less: -------------------------------------------------------------------------------- 1 | @import "node_modules/bootstrap/less/variables"; 2 | @import "node_modules/bootstrap/less/mixins"; 3 | @import "node_modules/bootstrap-chosen/bootstrap-chosen"; 4 | 5 | @chosen-sprite-path: "node_modules/bootstrap-chosen/chosen-sprite.png"; 6 | @chosen-sprite-retina-path: "node_modules/bootstrap-chosen/chosen-sprite@2x.png"; 7 | -------------------------------------------------------------------------------- /grails-app/assets/stylesheets/codemirror/codemirrorManifest.css: -------------------------------------------------------------------------------- 1 | /* 2 | *= require node_modules/codemirror/lib/codemirror.css 3 | *= require codemirror/warnings.css 4 | *= require node_modules/codemirror/addon/hint/show-hint.css 5 | */ -------------------------------------------------------------------------------- /grails-app/assets/stylesheets/csiDashboard/csiDashboard.less: -------------------------------------------------------------------------------- 1 | /* css for timepicker */ 2 | .ui-timepicker-div .ui-widget-header { 3 | margin-bottom: 8px; 4 | } 5 | 6 | .ui-timepicker-div dl { 7 | text-align: left; 8 | } 9 | 10 | .ui-timepicker-div dl dt { 11 | height: 25px; 12 | margin-bottom: -25px; 13 | } 14 | 15 | .ui-timepicker-div dl dd { 16 | margin: 0 10px 10px 65px; 17 | } 18 | 19 | .ui-timepicker-div td { 20 | font-size: 90%; 21 | } 22 | 23 | .ui-tpicker-grid-label { 24 | background: none; 25 | border: none; 26 | margin: 0; 27 | padding: 0; 28 | } 29 | 30 | #csiTypeSelect { 31 | height: 20px; 32 | } 33 | -------------------------------------------------------------------------------- /grails-app/assets/stylesheets/d3Charts/barChart.less: -------------------------------------------------------------------------------- 1 | // Variables 2 | @font: 18px sans-serif; 3 | 4 | .chart { 5 | font: @font; 6 | } 7 | 8 | .barRect { 9 | fill: steelblue; 10 | } 11 | 12 | .barRect:hover { 13 | fill: orange; 14 | } 15 | 16 | .chart text { 17 | fill: black; 18 | font-weight: bold; 19 | } 20 | 21 | .chart .axisLabel { 22 | fill: black; 23 | text-anchor: end; 24 | } 25 | 26 | .xAxis path, 27 | .xAxis line, 28 | .yAxis path, 29 | .yAxis line { 30 | fill: none; 31 | stroke: black; 32 | shape-rendering: inherit; 33 | } 34 | .yAxis text, 35 | .xAxis text { 36 | font: @font; 37 | } -------------------------------------------------------------------------------- /grails-app/assets/stylesheets/d3Charts/clocks.less: -------------------------------------------------------------------------------- 1 | svg.clock { 2 | stroke-linecap: round; 3 | } 4 | 5 | .hourtick.face { 6 | } 7 | 8 | .minutetick.face { 9 | stroke-width: 1; 10 | } 11 | 12 | .hand { 13 | stroke: #336; 14 | stroke-width: 2; 15 | } 16 | 17 | 18 | .clockBorder { 19 | fill: #e1e1e1; 20 | stroke: black; 21 | } -------------------------------------------------------------------------------- /grails-app/assets/stylesheets/d3Charts/d3chart.less: -------------------------------------------------------------------------------- 1 | /* 2 | This file contains CSS rules which are use by every d3 chart and 3 | must be imported in the corresponding LESS stylesheet of the chart 4 | */ 5 | 6 | @import "../variables-corporate"; 7 | 8 | 9 | // use bootstrap defined font properties in d3chart explicitly to get the right styles when downloading the PNG 10 | .d3chart * { 11 | font-family: @font-family-base; 12 | font-size: @font-size-base; 13 | color: @text-color; 14 | line-height: @line-height-base; 15 | } -------------------------------------------------------------------------------- /grails-app/assets/stylesheets/d3Charts/forceDirectedGraph.less: -------------------------------------------------------------------------------- 1 | // Variables 2 | @font: 16px sans-serif; 3 | 4 | .chart text { 5 | font: @font; 6 | } 7 | 8 | .nodeRect{ 9 | fill: #eeeeee; 10 | stroke: #9e9e9e; 11 | stroke-width: 2; 12 | stroke-opacity: 0.5; 13 | } 14 | 15 | .nodeSVG:hover .nodeRect{ 16 | fill: #dfcc21; 17 | } 18 | 19 | 20 | .browserTop{ 21 | fill: #9e9e9e; 22 | } 23 | 24 | .browserSearch { 25 | fill: #eeeeee; 26 | } 27 | 28 | .browserText :hover{ 29 | 30 | } 31 | 32 | .closeCircle{ 33 | fill: red; 34 | } 35 | .minCircle{ 36 | fill: yellow; 37 | } 38 | .maxCircle{ 39 | fill: green; 40 | } 41 | 42 | .node { 43 | fill: #c2d1c2; 44 | stroke: #fff; 45 | stroke-width: 2px; 46 | } 47 | 48 | .link { 49 | stroke: #777; 50 | stroke-width: 2px; 51 | } -------------------------------------------------------------------------------- /grails-app/assets/stylesheets/d3Charts/scheduleChart.less: -------------------------------------------------------------------------------- 1 | // Variables 2 | @font: 10px sans-serif; 3 | 4 | .axis text { 5 | font: @font; 6 | } 7 | 8 | .axis path, 9 | .axis line { 10 | fill: none; 11 | stroke: #000; 12 | shape-rendering: crispEdges; 13 | } 14 | 15 | .xAxisGrid path, 16 | .xAxisGrid line { 17 | fill: none; 18 | stroke: grey; 19 | stroke-dasharray: 2,2; 20 | } 21 | .xAxisGrid text { 22 | display: none; 23 | } 24 | 25 | .locationAxis path, 26 | .locationAxis line { 27 | fill: none; 28 | stroke: none; 29 | } 30 | 31 | .locationAxis text { 32 | font: @font; 33 | } 34 | 35 | .resetButton { 36 | fill: lightgrey; 37 | } 38 | 39 | .resetButtonText { 40 | fill: white; 41 | stroke: none; 42 | text-anchor: middle; 43 | } -------------------------------------------------------------------------------- /grails-app/assets/stylesheets/dimple/barchart.css: -------------------------------------------------------------------------------- 1 | 2 | #chart-container { 3 | position: relative; 4 | } 5 | 6 | #filter-dropdown-group { 7 | position: absolute; 8 | right: 60px; 9 | top: 10px; 10 | z-index: 2; 11 | padding: 6px 12px; 12 | } 13 | -------------------------------------------------------------------------------- /grails-app/assets/stylesheets/fontawesome.less: -------------------------------------------------------------------------------- 1 | /* 2 | *= require node_modules/@fortawesome/fontawesome-free/less/fontawesome 3 | *= require node_modules/@fortawesome/fontawesome-free/less/solid 4 | *= require node_modules/@fortawesome/fontawesome-free/less/regular 5 | *= require node_modules/@fortawesome/fontawesome-free/less/brands 6 | */ 7 | -------------------------------------------------------------------------------- /grails-app/assets/stylesheets/queueStatus/list.css: -------------------------------------------------------------------------------- 1 | .status { 2 | display: block; 3 | } 4 | .running { 5 | background: center left no-repeat url('../assets/images/spinner.gif'); 6 | padding-left: 20px; 7 | } 8 | .new-col-sec { 9 | border-left: 1px #ccc solid; 10 | } 11 | label { 12 | display: inline; 13 | } 14 | -------------------------------------------------------------------------------- /grails-app/assets/stylesheets/script/scriptManifest.css: -------------------------------------------------------------------------------- 1 | /* 2 | *= require codemirror/codemirrorManifest.css 3 | *= require script/versionControl.css 4 | */ -------------------------------------------------------------------------------- /grails-app/assets/stylesheets/tagit.css: -------------------------------------------------------------------------------- 1 | /* 2 | *= require node_modules/tag-it/css/jquery.tagit.css 3 | *= require node_modules/jquery-ui-dist/jquery-ui.css 4 | */ -------------------------------------------------------------------------------- /grails-app/controllers/de/iteratec/osm/security/RequestmapController.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.security 2 | 3 | class RequestmapController extends grails.plugin.springsecurity.ui.RequestmapController { 4 | } 5 | -------------------------------------------------------------------------------- /grails-app/controllers/de/iteratec/osm/security/SecurityInfoController.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.security 2 | 3 | class SecurityInfoController extends grails.plugin.springsecurity.ui.SecurityInfoController { 4 | } 5 | -------------------------------------------------------------------------------- /grails-app/domain/de/iteratec/osm/csi/CsiSystem.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.csi 2 | 3 | import de.iteratec.osm.measurement.schedule.JobGroup 4 | 5 | 6 | class CsiSystem { 7 | 8 | String label 9 | 10 | Collection jobGroupWeights = [] 11 | 12 | static hasMany = [jobGroupWeights: JobGroupWeight] 13 | 14 | static constraints = { 15 | label unique: true, blank: false 16 | jobGroupWeights minSize: 2, validator: {jobGroupWeights, object -> 17 | // All JobGroups have to be different 18 | jobGroupWeights*.jobGroup.unique(false).size() == jobGroupWeights*.jobGroup.size() 19 | } 20 | } 21 | 22 | List getAffectedJobGroups() { 23 | return jobGroupWeights*.jobGroup 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /grails-app/domain/de/iteratec/osm/csi/JobGroupWeight.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.csi 2 | 3 | import de.iteratec.osm.measurement.schedule.JobGroup 4 | 5 | class JobGroupWeight { 6 | JobGroup jobGroup 7 | Double weight 8 | 9 | static belongsTo = [csiSystem: CsiSystem] 10 | static constraints = { 11 | jobGroup validator: {return it.csiConfiguration != null} 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /grails-app/domain/de/iteratec/osm/report/external/GraphitePathCsiData.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.report.external 2 | 3 | import de.iteratec.osm.report.chart.AggregationType 4 | 5 | class GraphitePathCsiData { 6 | String prefix 7 | AggregationType aggregationType 8 | 9 | static belongsTo = [GraphiteServer] 10 | 11 | static constraints = { 12 | prefix(matches: /([a-zA-Z0-9]+\.)+/, nullable: false, blank: false, maxSize: 255) 13 | } 14 | 15 | @Override 16 | String toString(){ 17 | return "${prefix}[STATIC_PATH].${aggregationType}" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /grails-app/domain/de/iteratec/osm/report/external/GraphitePathRawData.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.report.external 2 | 3 | import de.iteratec.osm.result.Measurand 4 | import de.iteratec.osm.result.CachedView 5 | import de.iteratec.osm.util.Constants 6 | 7 | class GraphitePathRawData { 8 | String prefix 9 | Measurand measurand 10 | CachedView cachedView 11 | 12 | static belongsTo = [GraphiteServer] 13 | 14 | static constraints = { 15 | importFrom(GraphitePathCsiData) 16 | } 17 | 18 | @Override 19 | String toString(){ 20 | return "${prefix}[STATIC_PATH].${measurand}"+Constants.UNIQUE_STRING_DELIMITTER+"${cachedView}" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /grails-app/domain/de/iteratec/osm/result/UserTimingSelectionInformation.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.result 2 | 3 | class UserTimingSelectionInformation { 4 | String name 5 | UserTimingType type 6 | 7 | static belongsTo=[ResultSelectionInformation] 8 | 9 | static constraints = { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /grails-app/domain/de/iteratec/osm/security/Role.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.security 2 | 3 | import groovy.transform.EqualsAndHashCode 4 | import groovy.transform.ToString 5 | 6 | @EqualsAndHashCode(includes='authority') 7 | @ToString(includes='authority', includeNames=true, includePackage=false) 8 | class Role implements Serializable { 9 | 10 | private static final long serialVersionUID = 1 11 | 12 | String authority 13 | 14 | static constraints = { 15 | authority blank: false, unique: true 16 | } 17 | 18 | static mapping = { 19 | cache true 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /grails-app/domain/de/iteratec/osm/system/MissingJobResultCheck.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.system 2 | 3 | class MissingJobResultCheck { 4 | 5 | Date date 6 | Integer missingResults 7 | 8 | static constraints = { 9 | date(nullable: false) 10 | missingResults(nullable: false) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /grails-app/jobs/de/iteratec/osm/report/external/GraphiteEventCollectorJob.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.report.external 2 | 3 | /** 4 | * Triggers daily Graphite Event fetching 5 | */ 6 | class GraphiteEventCollectorJob { 7 | 8 | GraphiteEventService graphiteEventService 9 | boolean createBatchActivity = false 10 | 11 | static triggers = { 12 | /** Each Hour at Minute 30. */ 13 | cron(name: 'HourlyGraphiteEventCollection', cronExpression: '0 30 * ? * *') 14 | } 15 | 16 | def execute() { 17 | graphiteEventService.fetchGraphiteEvents(createBatchActivity, 60) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /grails-app/jobs/de/iteratec/osm/report/external/JobHealthReportJob.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.report.external 2 | 3 | import grails.util.Environment 4 | 5 | class JobHealthReportJob { 6 | 7 | JobHealthReportService jobHealthReportService 8 | 9 | static triggers = { 10 | /** Every five minutes. */ 11 | cron(name: 'JobHealthReport', cronExpression: '0 */5 * ? * * *') 12 | } 13 | 14 | def execute() { 15 | if (Environment.getCurrent() == Environment.PRODUCTION) { 16 | Date date = new Date() 17 | jobHealthReportService.reportJobHealthStatusToGraphite(date) 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /grails-app/jobs/de/iteratec/osm/system/LocationHealthCheckCleanupJob.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.system 2 | 3 | class LocationHealthCheckCleanupJob { 4 | 5 | LocationHealthCheckService locationHealthCheckService 6 | 7 | static triggers = { 8 | /** 9 | * Each Day at 2:15 am. 10 | */ 11 | cron(name: 'LocationHealthCheckCleanupJob', cronExpression: '0 15 2 ? * *') 12 | } 13 | 14 | def execute() { 15 | locationHealthCheckService.cleanupHealthChecks() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /grails-app/jobs/de/iteratec/osm/system/MissingJobResultCheckJob.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.system 2 | 3 | class MissingJobResultCheckJob { 4 | 5 | public static final int FREQUENCY_IN_HOURS = 1 6 | MissingJobResultCheckService missingJobResultCheckService 7 | 8 | static triggers = { 9 | cron(name: 'missingJobResultCheckJob', cronExpression: "0 0 */$FREQUENCY_IN_HOURS ? * *") 10 | } 11 | 12 | def execute() { 13 | missingJobResultCheckService.fillMissingJobResults() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /grails-app/migrations/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/grails-app/migrations/.gitignore -------------------------------------------------------------------------------- /grails-app/migrations/2015-11-18-DATA-multiply-csi-values-by-100.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: "nkuhn", id: "1447858496000-1") { 3 | sql(''' update measured_value set value = value * 100 where value <= 1; ''' ) 4 | } 5 | changeSet(author: "nkuhn", id: "1447858496000-2") { 6 | sql(''' update event_result set customer_satisfaction_in_percent = customer_satisfaction_in_percent * 100 where customer_satisfaction_in_percent <= 1; ''' ) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /grails-app/migrations/2015-11-18-DATA-set-initial-csi-transformation.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: "nkuhn", id: "1447854544000-1") { 3 | sql(''' update osm_configuration set csi_transformation = 'BY_MAPPING' ''' ) 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /grails-app/migrations/2015-12-22-DATA-delete-measured-value-update-events.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: "mmeier", id: "1450786890000-1") { 3 | sql(''' delete from measured_value_update_event where measured_value_id in ( 4 | select id from measured_value where closed_and_calculated = 1); ''' ) 5 | } 6 | changeSet(author: "mmeier", id: "1450786890000-2") { 7 | sql(''' delete from measured_value_update_event where measured_value_id not in ( 8 | select id from measured_value); ''' ) 9 | } 10 | } -------------------------------------------------------------------------------- /grails-app/migrations/2016-01-04-DATA-create-initial-browser-connectivity-weights.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: "nkuhn", id: "1451911470-1") { 3 | sql(''' 4 | INSERT INTO browser_connectivity_weight (version,browser_id,connectivity_id,weight) 5 | SELECT 0,b.id, c.id, b.weight 6 | FROM browser b CROSS JOIN connectivity_profile c 7 | WHERE b.weight > 0; 8 | ''' ) 9 | } 10 | } -------------------------------------------------------------------------------- /grails-app/migrations/2016-02-24-DATA-v341.groovy: -------------------------------------------------------------------------------- 1 | import de.iteratec.osm.report.UserspecificCsiDashboard 2 | 3 | databaseChangeLog = { 4 | changeSet(author: "bwo (generated)", id: "1456313431000-1") { 5 | sql(''' 6 | UPDATE userspecific_csi_dashboard SET csi_type_doc_complete=1; 7 | ''') 8 | } 9 | } -------------------------------------------------------------------------------- /grails-app/migrations/2016-03-04-SCHEME-v347.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | 3 | changeSet(author: "marcus (generated)", id: "1457079344288-1") { 4 | addColumn(tableName: "userspecific_csi_dashboard") { 5 | column(name: "selected_csi_systems", type: "varchar(255)") 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /grails-app/migrations/2016-09-30-SCHEME-v354.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: "nkuhn (generated)", id: "1475229633466-1") { 3 | addColumn(tableName: "event_result") { 4 | column(name: "one_based_step_index_in_journey", type: "integer") 5 | } 6 | } 7 | changeSet(author: "nkuhn (generated)", id: "1475704059884-1") { 8 | addColumn(tableName: "web_page_test_server") { 9 | column(name: "api_key", type: "varchar(255)") 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /grails-app/migrations/2017-02-23-SCHEME-v412.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: "marcus (generated)", id: "1487856496625-1") { 3 | addColumn(tableName: "batch_activity") { 4 | column(name: "comment", type: "varchar(255)") 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /grails-app/migrations/2017-03-21-DATA-v413.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | // so far only tcp connections were supported 3 | changeSet(author: 'mmi', id: '1490080349980-2') { 4 | sql('''UPDATE graphite_server SET report_protocol = 'TCP' ''') 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /grails-app/migrations/2017-05-19-DATA-v414.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | // so far only tcp connections were supported 3 | changeSet(author: 'dkl', id: '1495182423000-1') { 4 | sql('''UPDATE job SET save_bodies = 'ALL' WHERE bodies = 1''') 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /grails-app/migrations/2017-05-19-SCHEME-v414.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: "dkl", id: "1495182423000-2") { 3 | dropColumn(columnName: "bodies", tableName: "job") 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /grails-app/migrations/2017-06-13-DATA-v420_beta.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: 'nkuhn', id: '1497365028000-1') { 3 | sql('''UPDATE aggregator_type SET 4 | `measurand_group`='LOAD_TIMES' 5 | WHERE (`name`='speedIndexUncached' or `name`='speedIndexCached') and `measurand_group`='UNDEFINED';''') 6 | } 7 | changeSet(author: 'nkuhn', id: '1497450101000-1') { 8 | sql('''UPDATE osm_configuration SET `min_doc_complete_time_in_millisecs`=10 9 | WHERE `min_doc_complete_time_in_millisecs`=250;''') 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /grails-app/migrations/2017-06-16-SCHEME-v420_beta_2.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: "dkl", id: "1497618381-1") { 3 | addColumn(tableName: "job") { 4 | column(name: "trace_categories",defaultValue: "blink,v8,cc,gpu,blink.net,netlog,disabled-by-default-v8.runtime_stats", type: "varchar(255)") 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /grails-app/migrations/2017-06-21-SCHEME-v420_beta_2.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: "jweiss", id: "1498059027-1") { 3 | addColumn(tableName: "csi_aggregation") { 4 | column(name: "aggregation_type", type: "varchar(255)") 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /grails-app/migrations/2017-07-05-SCHEME-v420_beta_2.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: "jweiss", id: "1499269597-1") { 3 | renameColumn(tableName: "osm_configuration", oldColumnName: "min_doc_complete_time_in_millisecs", newColumnName: "min_valid_loadtime", columnDataType: "int") 4 | } 5 | changeSet(author: "jweiss", id: "1499269597-2") { 6 | renameColumn(tableName: "osm_configuration", oldColumnName: "max_doc_complete_time_in_millisecs", newColumnName: "max_valid_loadtime", columnDataType: "int") 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /grails-app/migrations/2017-07-10-SCHEME-v420_beta_2.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | 3 | changeSet(author: "mwg (generated)", id: "1499681004343-7") { 4 | dropTable(tableName: "graphite_server_graphite_path") 5 | } 6 | 7 | changeSet(author: "mwg (generated)", id: "1499681004343-6") { 8 | dropTable(tableName: "graphite_path") 9 | } 10 | 11 | changeSet(author: "mwg (generated)", id: "1499690731693-3") { 12 | dropTable(tableName: "aggregator_type") 13 | } 14 | } -------------------------------------------------------------------------------- /grails-app/migrations/2017-07-12-SCHEME-v420_beta_2.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: "mwg (generated)", id: "1499868526467-1") { 3 | addColumn(tableName: "event_result") { 4 | column(name: "consistently_interactive_in_millisecs", type: "integer") 5 | column(name: "first_interactive_in_millisecs", type: "integer") 6 | column(name: "visually_complete85in_millisecs", type: "integer") 7 | column(name: "visually_complete90in_millisecs", type: "integer") 8 | column(name: "visually_complete95in_millisecs", type: "integer") 9 | column(name: "visually_complete99in_millisecs", type: "integer") 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /grails-app/migrations/2017-07-18-DATA-v420_beta_2.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: "mwg", id: "1500367884-1") { 3 | sql(''' 4 | UPDATE event_result 5 | SET speed_index = null 6 | WHERE speed_index = -1; 7 | ''') 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /grails-app/migrations/2017-09-21-SCHEME-v432.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: "nkuhn", id: "1506008225000-1") { 3 | modifyDataType( 4 | tableName: "location", 5 | columnName: "location", 6 | newDataType: "varchar(255)" 7 | ) 8 | modifyDataType( 9 | tableName: "location", 10 | columnName: "label", 11 | newDataType: "varchar(255)" 12 | ) 13 | } 14 | } -------------------------------------------------------------------------------- /grails-app/migrations/2017-09-26-SCHEME-v433.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: "sburnicki", id: "1506428941541-1") { 3 | dropTable(tableName: "micro_service_api_key") 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /grails-app/migrations/2017-12-19-v440-addGlobalUAConfigColumn.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | 3 | changeSet(author: "fabian (generated)", id: "1513675981094-1") { 4 | addColumn(tableName: "osm_configuration") { 5 | column(name: "global_user_agent_suffix", type: "varchar(255)") 6 | } 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /grails-app/migrations/2017-12-19-v440-improveTimeSeriesPerformance.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: "nkuhn", id: "1513696035000-1") { 3 | createIndex(indexName: "forEventResultDashboard", tableName: "event_result") { 4 | column(name: "job_group_id") 5 | column(name: "page_id") 6 | column(name: "job_result_date") 7 | column(name: "connectivity_profile_id") 8 | column(name: "fully_loaded_time_in_millisecs") 9 | column(name: "median_value") 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /grails-app/migrations/2018-01-09-v440-addUseGlobalUASuffixBool.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | 3 | changeSet(author: "fabian (generated)", id: "1515502541622-1") { 4 | addColumn(tableName: "job") { 5 | column(name: "use_globaluasuffix", type: "bit") { 6 | constraints(nullable: "false") 7 | } 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /grails-app/migrations/2018-02-20-v450-dropMainUrl.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: "mwg (generated)", id: "1519139936827-2") { 3 | dropColumn(columnName: "main_url_under_test", tableName: "osm_configuration") 4 | } 5 | } -------------------------------------------------------------------------------- /grails-app/migrations/2018-06-20-v460-removeScriptPageRelations.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: "owe (generated)", id: "1529506430640-1") { 3 | sql(''' delete from script_page ''') 4 | } 5 | } -------------------------------------------------------------------------------- /grails-app/migrations/2018-09-27-SCHEME-v510-remove-csi-by-rank.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: "sburnicki", id: "1538037412000-1") { 3 | dropTable(tableName: "customer_frustration") 4 | dropColumn(columnName: "csi_transformation", tableName: "osm_configuration") 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /grails-app/migrations/2018-10-10-v500-locationHealthCheck-add-index.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | 3 | changeSet(author: "fwieczorek", id: "20181010-label-1") { 4 | 5 | createIndex(indexName: "date_and_location_id", tableName: "location_health_check") { 6 | column(name: "location_id") 7 | column(name: "date") 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /grails-app/migrations/2018-11-15-v500-hero-element-times.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | 3 | changeSet(author: "fwieczorek", id: "20181115-hero-elements") { 4 | addColumn(tableName: "job") { 5 | column(name: "hero_element_times", type: "boolean", valueBoolean: true) { 6 | constraints(nullable: "false") 7 | } 8 | 9 | column(name: "hero_elements", type: "text") { 10 | constraints(nullable: "true") 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /grails-app/migrations/2018-11-16-v500-add-new-measurands.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: "fwieczorek", id: "1542369419628-23") { 3 | addColumn(tableName: "event_result") { 4 | column(name: "js_total_bytes", type: "INT") 5 | column(name: "image_total_bytes", type: "INT") 6 | column(name: "css_total_bytes", type: "INT") 7 | column(name: "html_total_bytes", type: "INT") 8 | column(name: "first_meaningful_paint", type: "INT") 9 | column(name: "first_contentful_paint", type: "INT") 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /grails-app/migrations/2018-11-30-v500-remove-waterfall-url.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: "fho", id: "20181130-1") { 3 | dropColumn(columnName: "test_details_waterfallurl", tableName: "event_result") 4 | } 5 | } -------------------------------------------------------------------------------- /grails-app/migrations/2018-12-12-v500-nullable-job-result-label.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: "bwo", id: "20181212-1") { 3 | dropNotNullConstraint(columnName: 'job_config_label', tableName: 'job_result', columnDataType: 'varchar(255)') 4 | } 5 | } -------------------------------------------------------------------------------- /grails-app/migrations/2019-04-30-v512-browser-in-perf-aspect.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: "nkuhn (generated)", id: "1556619486219-1") { 3 | sql("delete from performance_aspect" ) 4 | } 5 | changeSet(author: "nkuhn (generated)", id: "1556619486219-2") { 6 | addColumn(tableName: "performance_aspect") { 7 | column(name: "browser_id", type: "bigint") { 8 | constraints(nullable: "false") 9 | } 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /grails-app/migrations/2019-06-19-add-user-timing-idx.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: "nkuhn (generated)", id: "1560938180861-3") { 3 | createIndex(indexName: "name_idx", tableName: "user_timing") { 4 | column(name: "name") 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /grails-app/migrations/2019-09-23-v530-add-first-paint-measurand.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | changeSet(author: "jwi", id: "1569252298504-1") { 3 | addColumn(tableName: "event_result") { 4 | column(name: "first_paint", type: "integer") 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /grails-app/services/de/iteratec/osm/OsmStateService.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm 2 | 3 | import de.iteratec.osm.measurement.environment.WebPageTestServer 4 | import de.iteratec.osm.measurement.schedule.Job 5 | import grails.gorm.transactions.Transactional 6 | 7 | @Transactional 8 | class OsmStateService { 9 | 10 | public boolean untouched() { 11 | return WebPageTestServer.count() == 0 && Job.count() == 0 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /grails-app/services/de/iteratec/osm/integrations/CiPipeService.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.integrations 2 | 3 | import de.iteratec.osm.measurement.schedule.Job 4 | import grails.gorm.transactions.Transactional 5 | 6 | @Transactional 7 | class CiPipeService { 8 | 9 | String getCiIntegrationScriptFor(Job job) { 10 | 11 | return this.class.classLoader.getResourceAsStream('OsmCiPipeCheck.groovy.template').text 12 | .replace('{{jobId}}', String.valueOf(job.ident())) 13 | .replace('{{wptServerBaseUrl}}', job?.location?.wptServer?.baseUrl) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /grails-app/services/de/iteratec/osm/report/external/GraphiteReportService.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.report.external 2 | 3 | import grails.gorm.transactions.Transactional 4 | 5 | @Transactional 6 | class GraphiteReportService { 7 | 8 | void report(long jobId, String testid) { 9 | Map dataMap = [jobId: jobId, 'testId': testid] 10 | GraphiteReportJob.schedule(new Date(), dataMap) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /grails-app/views/_common/_postloadInitializedJS.gsp: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /grails-app/views/_common/buttons/_editSymbolLink.gsp: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /grails-app/views/_common/buttons/_showSymbolLink.gsp: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /grails-app/views/_common/modals/_deleteSymbolLink.gsp: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | <%-- 7 | ${message(code: 'default.button.delete.label', default: 'Delete')} 8 | --%> 9 | ${message(code: 'default.button.delete.label', default: 'Delete')} 10 | 11 | -------------------------------------------------------------------------------- /grails-app/views/_common/modals/_deleteTextLink.gsp: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /grails-app/views/_common/modals/_registerTextLink.gsp: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 10 | 11 | 12 | <%-- --%> 13 | -------------------------------------------------------------------------------- /grails-app/views/_fields/_labelTemplate.gsp: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /grails-app/views/_fields/boolean/_wrapper.gsp: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |
6 |
-------------------------------------------------------------------------------- /grails-app/views/_fields/date/_wrapper.gsp: -------------------------------------------------------------------------------- 1 |
required"> 2 | 3 |
4 | 5 |
6 |
-------------------------------------------------------------------------------- /grails-app/views/_fields/enum/_wrapper.gsp: -------------------------------------------------------------------------------- 1 |
required"> 2 | 3 |
4 | 5 |
6 |
-------------------------------------------------------------------------------- /grails-app/views/_fields/manyToOne/_wrapper.gsp: -------------------------------------------------------------------------------- 1 |
required"> 2 | 3 |
4 | 5 |
6 |
-------------------------------------------------------------------------------- /grails-app/views/_fields/number/_wrapper.gsp: -------------------------------------------------------------------------------- 1 |
required"> 2 | 3 |
4 | 5 |
6 | 7 |
-------------------------------------------------------------------------------- /grails-app/views/_fields/oneToMany/_bidirectional.gsp: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /grails-app/views/_fields/oneToMany/_unidirectional.gsp: -------------------------------------------------------------------------------- 1 | <%@ page import="de.iteratec.osm.measurement.schedule.JobGroup" %> 2 | 4 | -------------------------------------------------------------------------------- /grails-app/views/_fields/oneToMany/_wrapper.gsp: -------------------------------------------------------------------------------- 1 |
2 | 3 | %{--Well that's one way, but their should be a "nice" way :/--}% 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | -------------------------------------------------------------------------------- /grails-app/views/_fields/oneToOne/_wrapper.gsp: -------------------------------------------------------------------------------- 1 |
required"> 2 | 3 |
4 | 5 |
6 |
7 | -------------------------------------------------------------------------------- /grails-app/views/_fields/string/_wrapper.gsp: -------------------------------------------------------------------------------- 1 |
required"> 2 | 3 |
4 | 5 |
6 |
-------------------------------------------------------------------------------- /grails-app/views/_menu/_menubar.gsp: -------------------------------------------------------------------------------- 1 |
2 | 6 |
7 | -------------------------------------------------------------------------------- /grails-app/views/_menu/_submenubarDeleteButton.gsp: -------------------------------------------------------------------------------- 1 | 2 |
  • 3 | 4 |
  • 5 |
    -------------------------------------------------------------------------------- /grails-app/views/_menu/_submenubarWithoutDelete.gsp: -------------------------------------------------------------------------------- 1 | 4 | 5 | <%-- Only show the "Pills" navigation menu if a controller exists (but not for home) --%> 6 | 13 | 18 | -------------------------------------------------------------------------------- /grails-app/views/_resultSelection/_repeatedViewCard.gsp: -------------------------------------------------------------------------------- 1 |
    2 |

    5 | 12 |
    13 | -------------------------------------------------------------------------------- /grails-app/views/_resultSelection/_timeRangePicker.gsp: -------------------------------------------------------------------------------- 1 |
    2 | 3 | 4 | 5 |
    6 | 7 | 8 | -------------------------------------------------------------------------------- /grails-app/views/angularFrontend.gsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <g:message code="default.product.title"/> 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /grails-app/views/chart/_csi-mappings.gsp: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /grails-app/views/csiSystem/_csiSystemTable.gsp: -------------------------------------------------------------------------------- 1 | <%@ page import="de.iteratec.osm.csi.CsiSystem" %> 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
    ${message(code: 'csiSystem.label.label', default: 'Label')}
    ${fieldValue(bean: csiSystemInstance, field: "label")}
    18 | -------------------------------------------------------------------------------- /grails-app/views/error.gsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Grails Runtime Exception 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /grails-app/views/graphiteEventSourcePath/show.gsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | <g:message code="default.show.label" args="[entityName]" /> 7 | 8 | 9 |
    10 | 11 |
    ${flash.message}
    12 |
    13 | 14 |
    15 | 16 | 17 | -------------------------------------------------------------------------------- /grails-app/views/graphiteServer/show.gsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | <g:message code="default.show.label" args="[entityName]" /> 7 | 8 | 9 |
    10 | 11 |
    ${flash.message}
    12 |
    13 | 14 |
    15 | 16 | 17 | -------------------------------------------------------------------------------- /grails-app/views/highchart/_chart.gsp: -------------------------------------------------------------------------------- 1 | 16 | 17 | -------------------------------------------------------------------------------- /grails-app/views/infrastructureSetup/index.gsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /grails-app/views/job/_blockTab.gsp: -------------------------------------------------------------------------------- 1 |
    2 | 5 |
    6 | 7 |

    8 |
    9 |
    10 | -------------------------------------------------------------------------------- /grails-app/views/job/_cancelLink.gsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | (${message(code: 'de.iteratec.isj.job.cancel')}) 4 | 5 | 6 | -------------------------------------------------------------------------------- /grails-app/views/job/_checkbox.gsp: -------------------------------------------------------------------------------- 1 |
    2 | 5 |
    6 |
    7 | 8 |
    9 |
    10 |
    -------------------------------------------------------------------------------- /grails-app/views/job/_checkboxTooltip.gsp: -------------------------------------------------------------------------------- 1 |
    2 | 8 |
    9 |
    10 | 11 |
    12 |
    13 |
    -------------------------------------------------------------------------------- /grails-app/views/job/_cronExpression.gsp: -------------------------------------------------------------------------------- 1 | 2 | ${it} 3 | -------------------------------------------------------------------------------- /grails-app/views/job/_customTab.gsp: -------------------------------------------------------------------------------- 1 |
    2 | 5 |
    6 | 7 |

    8 |
    9 |
    10 | -------------------------------------------------------------------------------- /grails-app/views/job/_inputField.gsp: -------------------------------------------------------------------------------- 1 |
    2 | 5 | 6 |
    7 | 9 |
    10 |
    -------------------------------------------------------------------------------- /grails-app/views/job/_inputFieldTooltip.gsp: -------------------------------------------------------------------------------- 1 |
    2 | 8 | 9 |
    10 | 12 |
    13 |
    -------------------------------------------------------------------------------- /grails-app/views/job/_jobStatusBar.gsp: -------------------------------------------------------------------------------- 1 |
    2 | 3 |  150 4 | 5 |  25 6 | 7 | 5 8 | 9 | 10 | 11 |
    12 | -------------------------------------------------------------------------------- /grails-app/views/job/_jobStatusBarHoverInfo.gsp: -------------------------------------------------------------------------------- 1 | 2 |
    3 | : 4 | 5 | 6 | < 80% < 7 | 8 | 9 | < 90% < 10 | 11 | 12 | 13 |
    14 | -------------------------------------------------------------------------------- /grails-app/views/job/_messages.gsp: -------------------------------------------------------------------------------- 1 | 2 |
    ${flash.message}
    3 |
    4 | 5 |
    6 | 7 |
    8 |
    9 | -------------------------------------------------------------------------------- /grails-app/views/job/_spofTab.gsp: -------------------------------------------------------------------------------- 1 |
    2 | 5 |
    6 | 7 |

    8 |
    9 |
    10 | -------------------------------------------------------------------------------- /grails-app/views/job/_thresholdsTab.gsp: -------------------------------------------------------------------------------- 1 | 2 |
    3 | 6 |
    7 |
    8 | 9 | -------------------------------------------------------------------------------- /grails-app/views/job/_updateHints.gsp: -------------------------------------------------------------------------------- 1 | 2 |
    3 |
    4 |
    5 |
    6 |
    -------------------------------------------------------------------------------- /grails-app/views/job/create.gsp: -------------------------------------------------------------------------------- 1 | <%=packageName%> 2 | -------------------------------------------------------------------------------- /grails-app/views/job/edit.gsp: -------------------------------------------------------------------------------- 1 | <%@ page import="de.iteratec.osm.measurement.schedule.Job; de.iteratec.osm.measurement.schedule.JobController" %> 2 | <%=packageName%> 3 | -------------------------------------------------------------------------------- /grails-app/views/layouts/_footer.gsp: -------------------------------------------------------------------------------- 1 | 2 |
    3 |
    4 | 5 |

    6 |
    7 | 8 |

    9 | 10 | Entwickelt von iteratec GmbH (Niederlassung Hamburg). 11 | 12 | 13 | Developed by iteratec GmbH (office Hamburg). 14 | 15 | Designed and built with Bootstrap. 16 |

    17 |
    18 |
    19 | -------------------------------------------------------------------------------- /grails-app/views/layouts/_optGroupedSelect.gsp: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /grails-app/views/measuredEvent/show.gsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <g:message code="default.show.label" args="[entityName]"/> 8 | 9 | 10 | 11 | 12 |
    13 | 14 |
    ${flash.message}
    15 |
    16 | 17 |
    18 | 19 | 20 | -------------------------------------------------------------------------------- /grails-app/views/measurementSetup/index.gsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /grails-app/views/page/_form.gsp: -------------------------------------------------------------------------------- 1 | <%@ page import="de.iteratec.osm.csi.Page" %> 2 | 3 |
    4 | 5 |
    6 | 7 |
    8 |
    9 | 10 | -------------------------------------------------------------------------------- /grails-app/views/page/_pageTable.gsp: -------------------------------------------------------------------------------- 1 | <%@ page import="de.iteratec.osm.csi.Page" %> 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
    ${message(code: 'page.name.label', default: 'Name')}
    ${fieldValue(bean: pageInstance, field: "name")}
    18 | -------------------------------------------------------------------------------- /grails-app/views/script/_messages.gsp: -------------------------------------------------------------------------------- 1 | 2 |
    3 | 4 |
    5 |
    -------------------------------------------------------------------------------- /grails-app/views/script/create.gsp: -------------------------------------------------------------------------------- 1 | <%=packageName%> 2 | -------------------------------------------------------------------------------- /grails-app/views/script/edit.gsp: -------------------------------------------------------------------------------- 1 | <%=packageName%> 2 | -------------------------------------------------------------------------------- /grails-app/views/tabularResultPresentation/_filterJob.gsp: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |

    4 | 5 |

    6 | ${job?.label} 7 |
    8 |
    9 | -------------------------------------------------------------------------------- /grails-app/views/templates/_fields/_list.gsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 |
    5 |
    ${body(p)}
    11 | -------------------------------------------------------------------------------- /lib/grails-rt.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/lib/grails-rt.jar -------------------------------------------------------------------------------- /scripts/DbmPortable.groovy: -------------------------------------------------------------------------------- 1 | target(default: "Murderizes default schema names from liquibase schemas") { 2 | new File( 'grails-app/migrations' ).eachFile{ file -> 3 | if( !file.name.startsWith( '.' ) ){ 4 | file.write( 5 | file.text.replaceAll( /(baseTableSchemaName: ".+?",)?(referencedTableSchemaName: ".+?",)?(schemaName: ".+?",)?/,'' ) 6 | ) 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /scripts/_Install.groovy: -------------------------------------------------------------------------------- 1 | // 2 | // This script is executed by Grails after plugin was installed to project. 3 | // This script is a Gant script so you can use all special variables provided 4 | // by Gant (such as 'baseDir' which points on project base dir). You can 5 | // use 'ant' to access a global instance of AntBuilder 6 | // 7 | // For example you can create directory under project tree: 8 | // 9 | // ant.mkdir(dir:"${basedir}/grails-app/jobs") 10 | // 11 | -------------------------------------------------------------------------------- /scripts/_Uninstall.groovy: -------------------------------------------------------------------------------- 1 | // 2 | // This script is executed by Grails when the plugin is uninstalled from project. 3 | // Use this script if you intend to do any additional clean-up on uninstall, but 4 | // beware of messing up SVN directories! 5 | // 6 | -------------------------------------------------------------------------------- /scripts/_Upgrade.groovy: -------------------------------------------------------------------------------- 1 | // 2 | // This script is executed by Grails during application upgrade ('grails upgrade' 3 | // command). This script is a Gant script so you can use all special variables 4 | // provided by Gant (such as 'baseDir' which points on project base dir). You can 5 | // use 'ant' to access a global instance of AntBuilder 6 | // 7 | // For example you can create directory under project tree: 8 | // 9 | // ant.mkdir(dir:"${basedir}/grails-app/jobs") 10 | // 11 | -------------------------------------------------------------------------------- /scripts/ci/building/merge_release_into_dev_and_master.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | git config --add remote.origin.fetch +refs/heads/*:refs/remotes/origin/* 4 | git fetch --all 5 | git remote set-url origin git@github.com:iteratec/OpenSpeedMonitor.git 6 | git remote -v 7 | git add . 8 | git commit -m "Committing package-lock.json and build.gradle of release" 9 | git push 10 | git checkout develop 11 | git merge release 12 | git push 13 | git checkout master 14 | git merge release 15 | git push -------------------------------------------------------------------------------- /scripts/ci/building/push_and_tag_dockerimage_travis.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | file="./version.properties" 4 | 5 | if [ -f "$file" ] 6 | then 7 | while IFS='=' read -r key value 8 | do 9 | key=$(echo $key | tr '.' '_') 10 | eval ${key}=${value} 11 | done < "$file" 12 | else 13 | echo "$file not found." 14 | fi 15 | 16 | function tagAndPush () { 17 | tag=$1 18 | docker tag iteratec/openspeedmonitor iteratec/openspeedmonitor:$tag 19 | docker push iteratec/openspeedmonitor:$tag 20 | } 21 | 22 | tagAndPush $app_version_major 23 | tagAndPush $app_version_minor 24 | tagAndPush $app_version_patch 25 | tagAndPush "latest" 26 | -------------------------------------------------------------------------------- /scripts/ci/debug/activate_mysql_slow_query_log.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | mysql -uroot -p${mysql_root_passwd} -e "SET @@global.long_query_time=${mysql_long_query_time};" # in seconds 3 | mysql -uroot -p${mysql_root_passwd} -e "SET @@global.slow_query_log_file=${mysql_slow_query_log_file};" 4 | mysql -uroot -p${mysql_root_passwd} -e "SET @@global.slow_query_log=1;" # enables slow query log -------------------------------------------------------------------------------- /scripts/ci/debug/deactivate_mysql_slow_query_log.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | mysql -uroot -p${mysql_root_passwd} -e "SET @@global.slow_query_log=0;" # disables slow query log -------------------------------------------------------------------------------- /scripts/ci/deploy/to_github.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | GITHUB_API_ACCESS_TOKEN_ITERASPEED=$bamboo_github_API_ACCESS_TOKEN_ITERASPEED 6 | 7 | GITHUB_REPOSITORY_URL=$bamboo_github_REPOSITORY_URL 8 | 9 | GITHUB_RELEASE_URL=$bamboo_github_RELEASE_URL 10 | 11 | 12 | # create github release ############################### 13 | 14 | echo "sending release notes to github" 15 | 16 | TAG_NAME=v$bamboo_ci_app_version 17 | RELEASE_NOTES="tbd" 18 | 19 | response=$(/usr/bin/curl -i -H "Authorization: token $GITHUB_API_ACCESS_TOKEN_ITERASPEED" -H "Accept: application/vnd.github+json" --data "{\"tag_name\": \"$TAG_NAME\", \"body\": \"$RELEASE_NOTES\"}" "$GITHUB_RELEASE_URL") 20 | status_code=$(echo "$response" | grep "HTTP/1.1" | cut -d" " -f 2) 21 | 22 | if [ $status_code -eq "201" ]; 23 | then 24 | return 0 25 | else 26 | return 1 27 | fi 28 | -------------------------------------------------------------------------------- /scripts/ci/deploy/war_deployment_via_curl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "ping $bamboo_tomcat_HOST_TO_DEPLOY_TO" 4 | ping -c 3 $bamboo_tomcat_HOST_TO_DEPLOY_TO 5 | mv *.war ROOT.war 6 | echo "deploy osm war to:" 7 | echo " http://$bamboo_tomcat_HOST_TO_DEPLOY_TO:$bamboo_tomcat_PORT_TO_DEPLOY/manager/text/deploy\?update\=true\&path\=" 8 | echo " war file:" 9 | ls -la ./*.war 10 | curl -T ./*.war -u $bamboo_tomcat_TOMCAT_ADMIN_USERNAME:$bamboo_tomcat_TOMCAT_ADMIN_PASSWORD \ 11 | http://$bamboo_tomcat_HOST_TO_DEPLOY_TO:$bamboo_tomcat_PORT_TO_DEPLOY/manager/text/deploy\?update\=true\&path\= \ 12 | > ./deploy_osm_war_output.txt 13 | 14 | curl_output=$(cat ./deploy_osm_war_output.txt) 15 | echo "$curl_output" 16 | if [[ $curl_output == *"Failed to deploy application"* ]] 17 | then 18 | exit 1; 19 | else 20 | exit 0; 21 | fi -------------------------------------------------------------------------------- /scripts/ci/github_deploy_key.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/scripts/ci/github_deploy_key.enc -------------------------------------------------------------------------------- /scripts/test/runGebTestsAndOpenReport.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd "`dirname $0`/../../" 3 | rm -rf build/spock-reports/** 4 | ./gradlew --stacktrace integrationTest --tests geb.**.* 5 | xdg-open build/spock-reports/index.html 6 | -------------------------------------------------------------------------------- /scripts/test/runIntegrationTestsAndOpenReport.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd "`dirname $0`/../../" 3 | rm -rf build/spock-reports/** 4 | ./gradlew integrationTest --tests de.**.* 5 | xdg-open build/spock-reports/index.html 6 | -------------------------------------------------------------------------------- /scripts/test/runJasmineTestsAndOpenReport.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd "`dirname $0`/../../" 3 | rm -rf build/spock-reports/** 4 | ./gradlew jasmineRun 5 | xdg-open build/reports/tests-jasmine/units.html 6 | -------------------------------------------------------------------------------- /scripts/test/runKarma.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd "`dirname $0`/../../" 3 | rm -rf build/spock-reports/** 4 | ./node_modules/karma/bin/karma start ./src/test/js/karma.conf.js 5 | -------------------------------------------------------------------------------- /scripts/test/runUnitTestsAndOpenReport.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd "`dirname $0`/../../" 3 | rm -rf build/spock-reports/** 4 | ./gradlew -x jasmineRun test 5 | xdg-open build/spock-reports/index.html 6 | -------------------------------------------------------------------------------- /src/integration-test/groovy/geb/IgnoreGebLiveTest.groovy: -------------------------------------------------------------------------------- 1 | package geb 2 | 3 | import groovy.transform.InheritConstructors 4 | 5 | /** 6 | * Ignore GebTests if it is run with test-app -Dgeb.liveTest 7 | */ 8 | @InheritConstructors 9 | class IgnoreGebLiveTest extends Closure{ 10 | Boolean doCall() { 11 | System.properties.containsKey('geb.liveTest') 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/integration-test/groovy/geb/pages/de/iteratec/osm/LandingPage.groovy: -------------------------------------------------------------------------------- 1 | package geb.pages.de.iteratec.osm 2 | 3 | class LandingPage extends I18nGebPage { 4 | 5 | 6 | static url = getUrl("/") 7 | 8 | static at = { 9 | title == getI18nMessage("default.product.title") 10 | } 11 | 12 | static content = { 13 | mainMenuEntryUser { $(".nav.navbar-nav.bottom li a", 0) } 14 | logoutLink { $("a[href='/logout/index']", 0) } 15 | } 16 | 17 | public void logoutActualUser(){ 18 | mainMenuEntryUser.click() 19 | logoutLink.click() 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/integration-test/groovy/geb/pages/de/iteratec/osm/LoginPage.groovy: -------------------------------------------------------------------------------- 1 | package geb.pages.de.iteratec.osm 2 | 3 | class LoginPage extends I18nGebPage { 4 | 5 | static url = getUrl("/login/auth") 6 | 7 | static at = { 8 | title == getI18nMessage("springSecurity.login.title") 9 | } 10 | 11 | 12 | static content = { 13 | loginForm { $("#loginForm") } 14 | 15 | username { loginForm.find("#username") } 16 | 17 | password { loginForm.find("#password") } 18 | 19 | submitButton { loginForm.find("input", type: "submit") } 20 | 21 | errorMessageBox { $("div.alert") } 22 | } 23 | } -------------------------------------------------------------------------------- /src/integration-test/groovy/geb/pages/de/iteratec/osm/batch/BatchActivityListPage.groovy: -------------------------------------------------------------------------------- 1 | package geb.pages.de.iteratec.osm.batch 2 | 3 | import geb.pages.de.iteratec.osm.I18nGebPage 4 | 5 | class BatchActivityListPage extends I18nGebPage{ 6 | static url = getUrl("/batchActivity/list") 7 | 8 | static at = { 9 | title == "Batch Activities List" 10 | } 11 | 12 | static content = { 13 | showOnlyActiveCheckbox{$("#filterBatchesByActiveCheckbox")} 14 | batchActivityTableRows{$("#batchActivityTable tbody tr")} 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/integration-test/groovy/geb/pages/de/iteratec/osm/csi/PageCreatePage.groovy: -------------------------------------------------------------------------------- 1 | package geb.pages.de.iteratec.osm.csi 2 | 3 | import de.iteratec.osm.csi.Page 4 | import geb.pages.de.iteratec.osm.I18nGebPage 5 | 6 | class PageCreatePage extends I18nGebPage{ 7 | static url = getUrl("/page/create") 8 | 9 | static at = { 10 | title == getI18nMessage("default.create.label", [Page.simpleName]) 11 | } 12 | 13 | static content = { 14 | pageNameTextField { $("#name") } 15 | pageWeightTextField { $("#weight") } 16 | 17 | createPageButton(to: [PageCreatePage, PageShowPage]) { $("#create") } 18 | 19 | errorMessageBox { $("div", class: "alert alert-danger") } 20 | errorMessageBoxText { errorMessageBox.attr("innerHTML") } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/integration-test/groovy/geb/pages/de/iteratec/osm/csi/PageIndexPage.groovy: -------------------------------------------------------------------------------- 1 | package geb.pages.de.iteratec.osm.csi 2 | 3 | import de.iteratec.osm.csi.Page 4 | import geb.pages.de.iteratec.osm.I18nGebPage 5 | 6 | class PageIndexPage extends I18nGebPage { 7 | static url = getUrl("/page/index") 8 | 9 | static at = { 10 | title == getI18nMessage("default.list.label", [Page.simpleName]) 11 | 12 | $("#Menu .active a").attr("href").contains("/page/index") 13 | } 14 | 15 | static content = { 16 | successDiv { $("div", class: "alert alert-info") } 17 | successDivText { successDiv[0].attr("innerHTML") } 18 | 19 | pageTableRows { $("#list-page").$("tbody").$("tr") } 20 | 21 | pageButtons { $(".pagination").$("li") } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/integration-test/groovy/geb/pages/de/iteratec/osm/measurement/environment/BrowserIndexPage.groovy: -------------------------------------------------------------------------------- 1 | package geb.pages.de.iteratec.osm.measurement.environment 2 | 3 | import geb.pages.de.iteratec.osm.I18nGebPage 4 | 5 | class BrowserIndexPage extends I18nGebPage { 6 | static url = getUrl("/browser/index") 7 | 8 | static at = { 9 | title == getI18nMessage("default.list.label", [getI18nMessage("browser.label")]) 10 | 11 | $("#Menu .active a").attr("href").contains("/browser/index") 12 | } 13 | 14 | static content = { 15 | 16 | successDiv { $("div", class: "alert alert-info") } 17 | successDivText { successDiv[0].attr("innerHTML") } 18 | 19 | browserTableRows { $("#list-browser").$("tbody").$("tr") } 20 | 21 | pageButtons { $(".pagination").$("li") } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/integration-test/groovy/geb/pages/de/iteratec/osm/measurement/environment/script/ScriptCreatePage.groovy: -------------------------------------------------------------------------------- 1 | package geb.pages.de.iteratec.osm.measurement.environment.script 2 | 3 | import geb.pages.de.iteratec.osm.I18nGebPage 4 | 5 | /** 6 | * @author nkuhn 7 | */ 8 | class ScriptCreatePage extends I18nGebPage{ 9 | 10 | static url = getUrl("/script/create") 11 | 12 | static at = { 13 | title == getI18nMessage("default.create.label", [getI18nMessage("de.iteratec.iss.script")]) 14 | } 15 | 16 | static content = { 17 | createButton { $("#saveButton") } 18 | nameInput { $("#label") } 19 | dangerAlerts { $(".alert.alert-danger ul li") } 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/integration-test/groovy/geb/pages/de/iteratec/osm/measurement/environment/script/ScriptListPage.groovy: -------------------------------------------------------------------------------- 1 | package geb.pages.de.iteratec.osm.measurement.environment.script 2 | 3 | import geb.pages.de.iteratec.osm.I18nGebPage 4 | 5 | /** 6 | * @author nkuhn 7 | */ 8 | class ScriptListPage extends I18nGebPage{ 9 | 10 | static url = getUrl("/script/list") 11 | 12 | static at = { 13 | title == getI18nMessage("de.iteratec.isocsi.scripts", [getI18nMessage("de.iteratec.isocsi.scripts")]) 14 | } 15 | 16 | static content = { 17 | createButton { $("a.btn.btn-primary.pull-right") } 18 | allScripts{$(".scriptLabel")} 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/java/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/src/java/.gitignore -------------------------------------------------------------------------------- /src/main/groovy/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/src/main/groovy/.gitignore -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/annotations/RestAction.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.annotations 2 | 3 | import java.lang.annotation.ElementType 4 | import java.lang.annotation.Retention 5 | import java.lang.annotation.RetentionPolicy 6 | import java.lang.annotation.Target 7 | 8 | /** 9 | * Created by jwi on 08/02/17. 10 | */ 11 | 12 | // Tag methods to destinct between REST call and normal requests 13 | @Target(ElementType.METHOD) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @interface RestAction { 16 | 17 | } -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/api/dto/ApplicationCsiDto.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.api.dto 2 | 3 | class ApplicationCsiDto { 4 | CsiDto[] csiValues 5 | boolean hasCsiConfiguration 6 | boolean hasJobResults 7 | boolean hasInvalidJobResults 8 | 9 | static ApplicationCsiDto createWithoutConfiguration() { 10 | ApplicationCsiDto dto = new ApplicationCsiDto() 11 | dto.hasCsiConfiguration = false 12 | dto.csiValues = [] 13 | return dto 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/api/dto/BatchActivityRowDto.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.api.dto 2 | 3 | /** 4 | * Created by nkuhn on 17.04.15. 5 | */ 6 | class BatchActivityRowDto { 7 | String htmlId 8 | String activity 9 | String status 10 | String progress 11 | String stage 12 | String lastFailureMessage 13 | String startDate 14 | String lastUpdated 15 | String endDate 16 | String statusEN 17 | String remainingTime 18 | } 19 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/api/dto/BrowserDto.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.api.dto 2 | 3 | import de.iteratec.osm.measurement.environment.Browser 4 | 5 | 6 | class BrowserDto { 7 | 8 | long id 9 | String name 10 | 11 | public static BrowserDto create(Browser browser) { 12 | BrowserDto result = new BrowserDto() 13 | 14 | result.id = browser.id 15 | result.name = browser.name 16 | 17 | return result 18 | } 19 | 20 | public static Collection create(Collection browsers) { 21 | Set result = [] 22 | 23 | browsers.each { 24 | result.add(create(it)) 25 | } 26 | 27 | return result 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/api/dto/CsiConfigurationDto.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.api.dto 2 | 3 | import de.iteratec.osm.csi.CsiConfiguration 4 | 5 | class CsiConfigurationDto { 6 | 7 | long id 8 | 9 | String label 10 | 11 | public static CsiConfigurationDto create(CsiConfiguration csiConfiguration) { 12 | CsiConfigurationDto result = new CsiConfigurationDto() 13 | 14 | result.id = csiConfiguration.id 15 | result.label = csiConfiguration.label 16 | 17 | return result 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/api/dto/CsiDto.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.api.dto 2 | 3 | class CsiDto { 4 | String date 5 | double csiDocComplete 6 | } 7 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/api/dto/CsiTranslationDto.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.api.dto 2 | 3 | /** 4 | * @author nkuhn 5 | */ 6 | class CsiTranslationDto { 7 | Integer loadTimeInMillisecs 8 | Double customerSatisfactionInPercent 9 | } 10 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/api/dto/DeviceTypeDto.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.api.dto 2 | 3 | /** 4 | * @author nkuhn 5 | */ 6 | class DeviceTypeDto { 7 | String name 8 | String icon 9 | } 10 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/api/dto/MeasurementResultDto.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.api.dto 2 | 3 | /** 4 | * Transport class for the threshold results. 5 | */ 6 | class MeasurementResultDto { 7 | String measuredEvent 8 | String measurand 9 | String unit 10 | Integer measuredValue 11 | Integer lowerBoundary 12 | Integer upperBoundary 13 | String evaluatedResult 14 | } -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/api/dto/PageCsiDto.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.api.dto 2 | 3 | import groovy.transform.EqualsAndHashCode 4 | 5 | @EqualsAndHashCode(includes = "pageId") 6 | class PageCsiDto { 7 | Long pageId 8 | String date 9 | double csiDocComplete 10 | } 11 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/api/dto/PageDto.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.api.dto 2 | 3 | import de.iteratec.osm.csi.Page 4 | 5 | 6 | class PageDto { 7 | 8 | long id 9 | String name 10 | 11 | public static PageDto create(Page page) { 12 | PageDto result = new PageDto() 13 | 14 | result.id = page.id 15 | result.name = page.name 16 | 17 | return result 18 | } 19 | 20 | public static Collection create(Collection pages) { 21 | Set result = [] 22 | 23 | pages.each { 24 | result.add(create(it)) 25 | } 26 | 27 | return result 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/barchart/BarchartDTO.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.barchart 2 | 3 | class BarchartDTO { 4 | List series = [] 5 | Map> filterRules = [:].withDefault {[]} 6 | Map i18nMap = [:] 7 | boolean hasComparativeData 8 | } 9 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/barchart/BarchartDatum.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.barchart 2 | 3 | class BarchartDatum { 4 | String measurand = "" 5 | String aggregationValue = "" 6 | Double value = null 7 | String grouping = "grouping" 8 | } 9 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/barchart/BarchartSeries.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.barchart 2 | 3 | class BarchartSeries { 4 | List data = [] 5 | String dimensionalUnit = "" 6 | String yAxisLabel = "" 7 | Boolean stacked = true 8 | } 9 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/barchart/PageComparisonAggregation.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.barchart 2 | 3 | class PageComparisonAggregation { 4 | BarchartAggregation baseAggregation 5 | BarchartAggregation comperativeAggregation 6 | } 7 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/batch/Activity.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.batch 2 | 3 | /** 4 | * Describes the goal of a BatchActivity 5 | */ 6 | enum Activity { 7 | DELETE ('de.iteratec.osm.batch.activity.DELETE'), 8 | UPDATE ('de.iteratec.osm.batch.activity.UPDATE'), 9 | CREATE ('de.iteratec.osm.batch.activity.CREATE') 10 | 11 | private final String i18nCode 12 | 13 | Activity (String i18nCode){ 14 | this.i18nCode = i18nCode 15 | } 16 | public String getI18nCode(){ 17 | return i18nCode 18 | } 19 | } -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/batch/Status.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.batch 2 | 3 | /** 4 | * Representation of the current status from a BatchActivity 5 | * 6 | * @author bwo 7 | */ 8 | enum Status { 9 | ACTIVE ('de.iteratec.osm.batch.status.ACTIVE'), 10 | INACTIVE ('de.iteratec.osm.batch.status.INACTIVE'), 11 | DONE ('de.iteratec.osm.batch.status.DONE'), 12 | CANCELLED ('de.iteratec.osm.batch.status.CANCELLED') 13 | 14 | private final String i18nCode 15 | 16 | Status(String i18nCode){ 17 | this.i18nCode = i18nCode 18 | } 19 | 20 | public String getI18nCode(){ 21 | return this.i18nCode 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/csi/CsiType.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.csi 2 | 3 | /** 4 | * This enum is used to decide on which value the csi data should be based 5 | */ 6 | enum CsiType { 7 | VISUALLY_COMPLETE, DOC_COMPLETE 8 | 9 | public static List getCsiTypes(CsiDashboardShowAllCommand command) { 10 | List csiTypes = [] 11 | if(command.csiTypeVisuallyComplete) csiTypes<< VISUALLY_COMPLETE 12 | if(command.csiTypeDocComplete) csiTypes<< DOC_COMPLETE 13 | return csiTypes 14 | } 15 | 16 | @Override 17 | String toString() { 18 | return super.toString().toLowerCase().replaceAll("_"," ") 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/csi/RickshawTransformableCsMapping.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.csi 2 | 3 | /** 4 | * Mappings build from entities of this type can be transfomed for representation in rickshaw charts. 5 | * @Author Created by nkuhn on 07.09.15. 6 | */ 7 | interface RickshawTransformableCsMapping { 8 | /** 9 | * Name of the group, this transformable mapping is associated to. All CsMappings with the same 10 | * name build one mapping rule. 11 | */ 12 | public String retrieveGroupingCriteria() 13 | /** 14 | * Load time of this mapping. 15 | */ 16 | public Integer retrieveLoadTimeInMilliSecs() 17 | /** 18 | * Customer satisfaction of this mapping. 19 | */ 20 | public Double retrieveCustomerSatisfactionInPercent() 21 | } -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/csi/UndefinedCsiTypeException.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.csi 2 | 3 | /** 4 | * Created by bwo on 11.02.16. 5 | */ 6 | class UndefinedCsiTypeException extends RuntimeException { 7 | 8 | 9 | public UndefinedCsiTypeException (boolean vc, boolean dc) { 10 | super("Undefined csi type: visually complete:$vc, doc complete:$dc") 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/d3Data/BarChartData.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.d3Data 2 | 3 | /** 4 | * This class represents a model for the creation of a d3 bar chart 5 | * A bar chart consists of a specified amount of ChartEntries containing a name and a weight 6 | */ 7 | class BarChartData { 8 | public static final String DEFAULT_X_LABEL = "x-Axis" 9 | public static final String DEFAULT_Y_LABEL = "y-Axis" 10 | List bars 11 | String xLabel 12 | String yLabel 13 | 14 | def BarChartData(){ 15 | bars = new ArrayList<>() 16 | xLabel = DEFAULT_X_LABEL 17 | yLabel = DEFAULT_Y_LABEL 18 | } 19 | 20 | def addDatum(ChartEntry c){ 21 | bars.add(c) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/d3Data/ChartEntry.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.d3Data 2 | 3 | /** 4 | * Class symbolizing a chart datum with a name and a value (weight) 5 | */ 6 | class ChartEntry { 7 | String name; 8 | 9 | double weight; 10 | } 11 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/d3Data/GetPageComparisonDataCommand.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.d3Data 2 | 3 | import grails.converters.JSON 4 | import grails.databinding.BindUsing 5 | import grails.validation.Validateable 6 | import org.joda.time.DateTime 7 | 8 | class GetPageComparisonDataCommand implements Validateable { 9 | DateTime from 10 | DateTime to 11 | @BindUsing({ obj, source -> 12 | return JSON.parse(source['selectedPageComparisons']) as List 13 | }) 14 | List selectedPageComparisons 15 | @BindUsing({ obj, source -> 16 | return JSON.parse(source['measurand']).measurands[0][0].replace("Uncached", "") 17 | }) 18 | String measurand 19 | 20 | List selectedDeviceTypes 21 | List selectedOperatingSystems 22 | 23 | String selectedAggregationValue 24 | } 25 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/d3Data/MatrixViewEntry.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.d3Data 2 | 3 | /** 4 | * This class represents a model a single entry in a matrix 5 | */ 6 | class MatrixViewEntry { 7 | 8 | public static final String DEFAULT_COLUMN_NAME = "horizontal" 9 | public static final String DEFAULT_ROW_NAME = "vertical" 10 | public static final BigDecimal DEFAULT_CELL_WEIGHT = 1.0 11 | 12 | String columnName 13 | String rowName 14 | Double weight 15 | 16 | MatrixViewEntry() { 17 | columnName = DEFAULT_COLUMN_NAME 18 | rowName = DEFAULT_ROW_NAME 19 | weight = DEFAULT_CELL_WEIGHT 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/d3Data/MultiLineChart.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.d3Data 2 | 3 | /** 4 | * Allocates data for a D3 multi line chart 5 | */ 6 | class MultiLineChart { 7 | public static final String DEFAULT_X_LABEL = "x-Axis" 8 | public static final String DEFAULT_Y_LABEL = "y-Axis" 9 | List lines 10 | 11 | String xLabel 12 | String yLabel 13 | 14 | MultiLineChart() { 15 | lines = new ArrayList<>() 16 | xLabel = DEFAULT_X_LABEL 17 | yLabel = DEFAULT_Y_LABEL 18 | } 19 | 20 | def addLine(MultiLineChartLineData line) { 21 | lines.add(line) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/distributionData/DistributionChartDTO.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.distributionData 2 | 3 | class DistributionChartDTO { 4 | Map series = new HashMap() 5 | Map> filterRules = [:].withDefault {[]} 6 | String dimensionalUnit = "" 7 | Map i18nMap = [:] 8 | } 9 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/distributionData/DistributionTrace.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.distributionData 2 | 3 | class DistributionTrace { 4 | String jobGroup = "" 5 | String page = "" 6 | List data = [] 7 | } 8 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/distributionData/Violin.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.distributionData 2 | 3 | class Violin { 4 | String identifier = "" 5 | String jobGroup = "" 6 | String page = "" 7 | List data = [] 8 | } -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/distributionData/ViolinChartDTO.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.distributionData 2 | 3 | class ViolinChartDTO { 4 | List series = [] 5 | Map> filterRules = [:].withDefault {[]} 6 | String measurandGroup = "" 7 | String dimensionalUnit = "" 8 | } 9 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/linechart/SummaryLabel.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.linechart 2 | 3 | class SummaryLabel { 4 | String key = "" 5 | String label = "" 6 | 7 | SummaryLabel(String key, String label) { 8 | this.key = key 9 | this.label = label 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/linechart/TimeSeries.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.linechart 2 | 3 | class TimeSeries { 4 | String identifier = "" 5 | String measurand = "" 6 | String jobGroup = "" 7 | String measuredEvent = "" 8 | String location = "" 9 | String connectivity = "" 10 | List data = [] 11 | } -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/linechart/TimeSeriesChartDTO.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.linechart 2 | 3 | class TimeSeriesChartDTO { 4 | Map> series = [:] 5 | Map measurandGroups = [:] 6 | List summaryLabels = [] 7 | int numberOfTimeSeries = 0 8 | } 9 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/linechart/TimeSeriesDataPoint.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.linechart 2 | 3 | class TimeSeriesDataPoint { 4 | Date date = new Date() 5 | Double value = 0.0 6 | String agent = "" 7 | TimeSeriesDataPointWptInfo wptInfo = null 8 | } 9 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/linechart/TimeSeriesDataPointWptInfo.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.linechart 2 | 3 | class TimeSeriesDataPointWptInfo { 4 | String baseUrl = "" 5 | String testId = "" 6 | Integer runNumber = 0 7 | Integer indexInJourney = 0 8 | } 9 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/measurement/environment/LocationWithXmlNode.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.measurement.environment 2 | 3 | import groovy.util.slurpersupport.GPathResult 4 | 5 | /** 6 | * Small wrapper for {@link Location}s with further attributes in health check functionality 7 | * @author nkuhn 8 | */ 9 | class LocationWithXmlNode { 10 | Location location 11 | GPathResult locationXmlNode 12 | } 13 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/measurement/environment/wptserver/OsmResultPersistanceException.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.measurement.environment.wptserver 2 | 3 | /** 4 | * Used in {@link EventResultPersisterService}. 5 | * Created by nkuhn on 17.03.16. 6 | */ 7 | class OsmResultPersistanceException extends Exception{ 8 | public OsmResultPersistanceException(String message){ 9 | super(message) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/measurement/environment/wptserver/Protocol.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.measurement.environment.wptserver 2 | 3 | /** 4 | * Created by nkuhn on 29.05.15. 5 | */ 6 | enum Protocol{ 7 | HTTP(80, 'http://'), 8 | HTTPS(443, 'https://'); 9 | 10 | private final int defaultPort 11 | private final String scheme 12 | 13 | Protocol(int defaultPort, String scheme){ 14 | this.defaultPort = defaultPort 15 | this.scheme = scheme 16 | } 17 | 18 | public int defaultPort(){ 19 | return this.defaultPort 20 | } 21 | public String scheme(){ 22 | return this.scheme 23 | } 24 | } -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/measurement/schedule/FailedJobResultDTO.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.measurement.schedule 2 | 3 | import de.iteratec.osm.result.JobResult 4 | 5 | import java.text.SimpleDateFormat 6 | 7 | class FailedJobResultDTO { 8 | String testId 9 | String date 10 | String jobResultStatus 11 | String wptStatus 12 | String description 13 | URL testUrl 14 | 15 | FailedJobResultDTO(JobResult jobResult) { 16 | testId = jobResult.testId 17 | date = new SimpleDateFormat().format(jobResult.date) 18 | jobResultStatus = jobResult.jobResultStatus.getMessage() 19 | wptStatus = jobResult.wptStatus.getMessage() 20 | description = jobResult.description 21 | testUrl = jobResult.tryToGetTestsDetailsURL() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/report/chart/AggregationType.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.report.chart 2 | 3 | enum AggregationType { 4 | MEASURED_EVENT, 5 | PAGE, 6 | JOB_GROUP, 7 | CSI_SYSTEM 8 | } -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/report/chart/OsmRickshawChart.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.report.chart 2 | 3 | /** 4 | * Contains data necessary to create a chart with rickshaw charting library. 5 | * Could contain all necessary data. At the moment some data (e.g. axis) iprovided separately. 6 | * 7 | * @author Created by nkuhn on 23.10.15. 8 | * @see http://code.shutterstock.com/rickshaw/ 9 | */ 10 | class OsmRickshawChart { 11 | /** 12 | * All graphs to draw. 13 | * Parts common in all graph labels are removed from labels. 14 | */ 15 | List osmChartGraphs 16 | /** 17 | * Common parts of all graph labels. 18 | */ 19 | String osmChartGraphsCommonLabel 20 | } 21 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/report/chart/RepresentableWptResult.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.report.chart 2 | 3 | /** 4 | * Just a marker interface. 5 | * @author nkuhn 6 | */ 7 | interface RepresentableWptResult { 8 | 9 | } -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/report/chart/page/EntryAndFollowDto.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.report.chart.page 2 | 3 | /** 4 | * @author nkuhn 5 | */ 6 | class EntryAndFollowDto { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/report/external/MockedGraphiteSocket.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.report.external 2 | 3 | /** 4 | * @author nkuhn 5 | */ 6 | class MockedGraphiteSocket implements GraphiteSocket{ 7 | class SentDate { 8 | GraphitePathName path 9 | Double value 10 | Date timestamp 11 | } 12 | List sentDates = [] 13 | 14 | @Override 15 | void sendDate(GraphitePathName path, double value, Date timestamp) throws NullPointerException, GraphiteComunicationFailureException { 16 | sentDates.add(new SentDate(path: path, value: value, timestamp: timestamp)) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/result/MeasurandGroup.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.result 2 | /** 3 | * To group {@link de.iteratec.osm.report.chart.AggregatorType}s which are measureands. 4 | * 5 | * @author nkuhn 6 | * 7 | */ 8 | enum MeasurandGroup { 9 | LOAD_TIMES(Unit.MILLISECONDS), 10 | REQUEST_COUNTS(Unit.NUMBER), 11 | REQUEST_SIZES(Unit.MEGABYTE), 12 | PERCENTAGES(Unit.PERCENT) 13 | 14 | private Unit unit 15 | 16 | private MeasurandGroup(Unit unit){ 17 | this.unit = unit 18 | } 19 | Unit getUnit(){ 20 | return unit 21 | } 22 | } -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/result/PerformanceAspectType.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.result 2 | 3 | enum PerformanceAspectType { 4 | PAGE_CONSTRUCTION_STARTED(Measurand.START_RENDER, 'fas fa-hourglass-start', Unit.MILLISECONDS), 5 | PAGE_SHOWS_USEFUL_CONTENT(Measurand.VISUALLY_COMPLETE, 'fas fa-eye', Unit.MILLISECONDS), 6 | PAGE_IS_USABLE(Measurand.TIME_TO_INTERACTIVE, 'fas fa-hand-pointer', Unit.MILLISECONDS) 7 | 8 | Measurand defaultMetric 9 | String icon 10 | Unit unit 11 | 12 | private PerformanceAspectType(Measurand value, String i, Unit u) { 13 | defaultMetric = value 14 | icon = i 15 | unit = u 16 | } 17 | } -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/result/TabularResultListResultsForSpecificJobCommand.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.result 2 | 3 | import de.iteratec.osm.measurement.schedule.Job 4 | 5 | /** 6 | * Created by msk on 04.04.2016. 7 | */ 8 | public class TabularResultListResultsForSpecificJobCommand extends TabularResultEventResultsCommandBase { 9 | Job job 10 | 11 | static constraints = { job(nullable: false) } 12 | 13 | @Override 14 | public void copyRequestDataToViewModelMap(Map viewModelToCopyTo) 15 | { 16 | super.copyRequestDataToViewModelMap(viewModelToCopyTo) 17 | viewModelToCopyTo.put('job', this.job) 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/result/Unit.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.result 2 | 3 | enum Unit{ 4 | KILOBYTE("KB",1000), 5 | MEGABYTE("MB",1000000), 6 | MILLISECONDS("ms",1), 7 | SECONDS("s",1000), 8 | PERCENT("%",1), 9 | NUMBER("#",1), 10 | OTHER("",1) 11 | 12 | private String label 13 | private Double divisor 14 | 15 | 16 | private Unit(String label,Double divisor){ 17 | this.label = label 18 | this.divisor = divisor 19 | } 20 | 21 | String getLabel(){ 22 | return label 23 | } 24 | 25 | Double getDivisor(){ 26 | return divisor 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/result/UserTimingType.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.result 2 | 3 | /** 4 | * Created by mwg on 19.07.2017. 5 | */ 6 | enum UserTimingType { 7 | MARK(MeasurandGroup.LOAD_TIMES, "userTimes", SelectedMeasurandType.USERTIMING_MARK ), 8 | MEASURE(MeasurandGroup.LOAD_TIMES, "userTimingMeasures", SelectedMeasurandType.USERTIMING_MEASURE), 9 | HERO_MARK(MeasurandGroup.LOAD_TIMES, "heroTimes", SelectedMeasurandType.HEROTIMING_MARK) 10 | 11 | MeasurandGroup measurandGroup 12 | String tagInResultXml 13 | SelectedMeasurandType selectedMeasurandType 14 | 15 | private UserTimingType(MeasurandGroup group, String groupTag, SelectedMeasurandType type){ 16 | measurandGroup = group 17 | tagInResultXml = groupTag 18 | selectedMeasurandType = type 19 | } 20 | } -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/result/dao/EventResultProjection.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.result.dao 2 | 3 | import de.iteratec.osm.report.chart.RepresentableWptResult 4 | import groovy.transform.EqualsAndHashCode 5 | /** 6 | * Created by mwg on 20.09.2017. 7 | */ 8 | @EqualsAndHashCode(excludes = ["projectedProperties"]) 9 | class EventResultProjection implements RepresentableWptResult{ 10 | 11 | def id 12 | 13 | Map projectedProperties = [:] 14 | 15 | def get(String property) { 16 | return projectedProperties.get(property) 17 | } 18 | String toString(){ 19 | StringBuilder sb = new StringBuilder() 20 | .append("[${this.id}] ") 21 | .append(this.projectedProperties) 22 | return sb.toString() 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/result/dao/MeasurandDto.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.result.dao 2 | 3 | class MeasurandDto { 4 | String id 5 | String name 6 | Boolean isUserTiming 7 | } 8 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/result/dao/PerformanceAspectTypeDto.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.result.dao 2 | 3 | class PerformanceAspectTypeDto { 4 | String name 5 | String icon 6 | String unit 7 | } 8 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/result/dao/query/MeasurandTrim.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.result.dao.query 2 | 3 | import de.iteratec.osm.result.Measurand 4 | import de.iteratec.osm.result.MeasurandGroup 5 | 6 | /** 7 | * @author nkuhn 8 | */ 9 | class MeasurandTrim { 10 | MeasurandGroup measurandGroup 11 | Measurand onlyForSpecific 12 | def value 13 | TrimQualifier qualifier 14 | } 15 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/result/dao/query/ProjectionProperty.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.result.dao.query 2 | 3 | import groovy.transform.EqualsAndHashCode 4 | 5 | /** 6 | * @author nkuhn 7 | */ 8 | @EqualsAndHashCode(excludes = ['alias']) 9 | class ProjectionProperty { 10 | String dbName 11 | String alias 12 | } 13 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/result/dao/query/TrimQualifier.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.result.dao.query 2 | 3 | /** 4 | * @author nkuhn 5 | */ 6 | enum TrimQualifier { 7 | 8 | GREATER_THAN('gt'), 9 | LOWER_THAN('lt') 10 | 11 | private String gorm 12 | 13 | private TrimQualifier(String gorm) { 14 | this.gorm = gorm 15 | } 16 | 17 | String getGormSyntax() { 18 | return this.gorm 19 | } 20 | } -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/result/dao/query/projector/EventResultProjector.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.result.dao.query.projector 2 | 3 | import de.iteratec.osm.result.SelectedMeasurand 4 | import de.iteratec.osm.result.dao.query.ProjectionProperty 5 | 6 | interface EventResultProjector { 7 | 8 | Closure generateSelectedMeasurandProjectionFor(List measurands, Set baseProjections) 9 | } 10 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/result/dao/query/transformer/EventResultTransformer.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.result.dao.query.transformer 2 | 3 | import de.iteratec.osm.result.dao.EventResultProjection 4 | 5 | interface EventResultTransformer { 6 | 7 | List transformRawQueryResult(List rawQueryData) 8 | } 9 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/result/dao/query/trimmer/EventResultTrimmer.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.result.dao.query.trimmer 2 | 3 | import de.iteratec.osm.result.SelectedMeasurand 4 | import de.iteratec.osm.result.dao.query.MeasurandTrim 5 | 6 | interface EventResultTrimmer { 7 | 8 | List buildTrims(List measurands, List trims) 9 | } 10 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/result/dto/AggregationChartDTO.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.result.dto 2 | 3 | class AggregationChartDTO { 4 | List series = [] 5 | Map> filterRules = [:].withDefault {[]} 6 | Map i18nMap = [:] 7 | boolean hasComparativeData 8 | } 9 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/result/dto/AggregationChartSeriesDTO.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.result.dto 2 | 3 | import groovy.transform.EqualsAndHashCode 4 | 5 | @EqualsAndHashCode 6 | class AggregationChartSeriesDTO { 7 | String measurand = "" 8 | String measurandLabel = "" 9 | String measurandGroup = "" 10 | Double value = null 11 | Double valueComparative = null 12 | String page = "" 13 | String jobGroup = "" 14 | String unit = "" 15 | String browser = "" 16 | String aggregationValue = "" 17 | String deviceType 18 | String operatingSystem 19 | } -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/result/dto/JobGroupDTO.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.result.dto 2 | 3 | class JobGroupDTO { 4 | String aggregationValue = "" 5 | String jobGroup = "" 6 | String browser = "" 7 | Double value = null 8 | } 9 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/util/DataIntegrityViolationExpectionUtil.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.util 2 | 3 | import org.springframework.dao.DataIntegrityViolationException 4 | 5 | /** 6 | * Created by mwg on 11.09.2017. 7 | */ 8 | class DataIntegrityViolationExpectionUtil { 9 | 10 | static String getEntityNameForForeignKeyViolation(DataIntegrityViolationException exception){ 11 | if(exception.cause.SQLState == "23000"){ 12 | return toCamelCase(exception.message.find("(`[A-Za-z_0-9]+`.`[a-z_]+`)").find("(.`[a-z_]+`)").find("[a-z_]+")) 13 | } 14 | return null 15 | } 16 | 17 | private static String toCamelCase( String text ) { 18 | text = text.replaceAll( "(_)([A-Za-z0-9])", { Object[] it -> it[2].toUpperCase() } ) 19 | return text.capitalize() 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/groovy/de/iteratec/osm/util/MessagePropertiesTrait.groovy: -------------------------------------------------------------------------------- 1 | package de.iteratec.osm.util 2 | 3 | trait MessagePropertiesTrait { 4 | Properties getMessageKeys(Locale locale) { 5 | this.getMergedProperties(locale).properties 6 | } 7 | 8 | Properties getPluginMessageKeys(Locale locale) { 9 | this.getMergedPluginProperties(locale).properties 10 | } 11 | } -------------------------------------------------------------------------------- /src/main/resources/public/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iteratec/OpenSpeedMonitor/c80ddc2c7491b82a6261e3b2ddc5ea06f90bf823/src/main/resources/public/.gitkeep -------------------------------------------------------------------------------- /src/main/resources/public/i18n/README.md: -------------------------------------------------------------------------------- 1 | **Do not edit i18n json files in this directory manually!** 2 | 3 | They get generated automatically from gradle build and all files created or edited manually here get removed. 4 | 5 | The frontend i18n json files get created based on grails i18n message bundles (located in `/grails-app/i18n/`). 6 | Every entry in these bundles with the prefix `frontend.` get transfered to frontend json files. 7 | 8 | So, for OpenSpeedMonitor the grails message bundles are the single truth for translated content and everything 9 | prefixed with `frontend.` is propageted to frontends i18n json bundles. 10 | -------------------------------------------------------------------------------- /src/main/templates/scaffolding/ScaffoldedController.groovy: -------------------------------------------------------------------------------- 1 | <%=packageName ? "package ${packageName}" : ''%> 2 | 3 | class ${className}Controller { 4 | 5 | static scaffold = ${className} 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/templates/scaffolding/index.gsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | <g:message code="default.list.label" args="[entityName]" /> 7 | 8 | 9 |
    10 | 11 |
    \${flash.message}
    12 |
    13 | 14 | 15 |
    16 | 17 |
    18 |
    19 | 20 | -------------------------------------------------------------------------------- /src/main/templates/scaffolding/show.gsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | <g:message code="default.show.label" args="[entityName]" /> 7 | 8 | 9 |
    10 | 11 |
    \${flash.message}
    12 |
    13 | 14 |
    15 | 16 | 17 | -------------------------------------------------------------------------------- /src/test/resources/CsiData/BROWSER_CONNECTIVITY_COMBINATION_weights.csv: -------------------------------------------------------------------------------- 1 | browser;connectivity;weight 2 | Browser1;DSL1;45.0 3 | Browser2;DSL2;12.0 -------------------------------------------------------------------------------- /src/test/resources/CsiData/BROWSER_CONNECTIVITY_COMBINATION_weights_should_fail.csv: -------------------------------------------------------------------------------- 1 | browser;connectivity 2 | Browser1;DSL1;45.0 3 | Browser2;DSL2;45.0 4 | galaxyS4;3G;4,0 -------------------------------------------------------------------------------- /src/test/resources/CsiData/DefaultMappings.csv: -------------------------------------------------------------------------------- 1 | name;loadTimeInMilliSecs;customerSatisfactionInPercent 2 | default1;0;100.0 3 | default1;200;75.0 4 | default1;500;30.5 5 | default2;0;95.0 6 | default2;200;80.3 7 | default2;500;12.0 8 | default3;0;100.0 9 | default3;200;79.9 10 | default3;500;50.0 11 | default3;1000;5.0 -------------------------------------------------------------------------------- /src/test/resources/CsiData/HOUROFDAY_weights.csv: -------------------------------------------------------------------------------- 1 | fullHour;weight 2 | 0;2.9 3 | 1;0.4 4 | 2;0.2 5 | 3;0.1 6 | 4;0.1 7 | 5;0.2 8 | 6;0.7 9 | 7;1.7 10 | 8;3.2 11 | 9;4.8 12 | 10;5.6 13 | 11;5.7 14 | 12;5.5 15 | 13;5.8 16 | 14;5.9 17 | 15;6.0 18 | 16;6.7 19 | 17;7.3 20 | 18;7.6 21 | 19;8.8 22 | 20;9.3 23 | 21;7.0 24 | 22;3.6 25 | 23;0.9 -------------------------------------------------------------------------------- /src/test/resources/CsiData/HOUROFDAY_weights_should_fail.csv: -------------------------------------------------------------------------------- 1 | fullHour;weight 2 | 0;2.9 3 | 1;0.4 4 | 2;0.2 5 | 3;0.1 6 | 4;0.1 7 | 5;0.2 8 | 6;0.7 9 | 7;1.7 10 | 8;3.2 11 | 9;4.8 12 | 10;5.6 13 | 11;5.7 14 | 12;5.5 15 | 13;5.8 16 | 14;5.9 17 | 15;6.0 18 | 16;6.7 19 | 17;7.3 20 | 18;7.6 21 | 19;8.8 22 | 20;9.3 23 | 21;7.0 24 | 22;3.6 25 | 23;0.9 26 | 24;0.9 -------------------------------------------------------------------------------- /src/test/resources/CsiData/HOUROFDAY_weights_should_fail_2.csv: -------------------------------------------------------------------------------- 1 | fullHour;weight 2 | 0;2.9 3 | 1;0.4 4 | 2;0.2 5 | 3;0.1 6 | 4;0.1 7 | 5;0.2 8 | 6;0.7 9 | 7;1.7 10 | 8;3.2 11 | 9;4.8 12 | 10;5.6 13 | 11;5.7 14 | 12;5.5 15 | 13;5.8 16 | 14;5.9 17 | 15;6.0 18 | 16;6.7 19 | 19;8.8 20 | 20;9.3 21 | 21;7.0 22 | 22;3.6 23 | 23;0.9 -------------------------------------------------------------------------------- /src/test/resources/CsiData/PAGE_weights.csv: -------------------------------------------------------------------------------- 1 | name;weight 2 | HP;12.0 3 | MES;3.4 4 | SE;6.7 5 | ADS;0.3 6 | WKBS;45.0 7 | WK;26.1 -------------------------------------------------------------------------------- /src/test/resources/CsiData/PAGE_weights_should_fail.csv: -------------------------------------------------------------------------------- 1 | name;weight 2 | HP;0.5 3 | MES;12.5 4 | SE;21 5 | ADS;3.4 6 | WKBS;6.3 7 | WK;12,5 -------------------------------------------------------------------------------- /src/test/resources/CsiData/TimeToCsMapping/expectedValues.csv: -------------------------------------------------------------------------------- 1 | Page;loadTimeInMillisec;CustomerSatisfaction 2 | HP_entry;4036;50 3 | HP_entry;1980;73.5 4 | HP_entry;3793;50 5 | HP_entry;6675;15.5 6 | HP_entry;2541;66.33165829000001 7 | HP_entry;2173;73.5 8 | HP_entry;2178;73.5 9 | HP_entry;2047;73.5 10 | HP_entry;2272;73 11 | HP_entry;6630;17 -------------------------------------------------------------------------------- /src/test/resources/GraphiteEvents/GraphiteEventServiceSpec_retreive_events.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "target": "my-graph", 4 | "datapoints": [[0.05, 1432871950], [0.05, 1432871960], [0.05, 1432871970], [0.05, 1432871980], [0.05, 1432871990], [0.05, 1432872000]], 5 | } 6 | ] -------------------------------------------------------------------------------- /src/test/resources/WptResultXmls/README: -------------------------------------------------------------------------------- 1 | This folder contains xml-files of wpt-results delivered from REST-API of wpt-servers 2 | (see https://sites.google.com/a/webpagetest.org/docs/advanced-features/webpagetest-restful-apis). 3 | 4 | Prefix of filename defines version of wptserver result comes from respective enum de.iteratec.osm.result.WptXmlResultVersion. --------------------------------------------------------------------------------