Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@ yarn-error.log
# Ignore Docker-specific files
.dockerignore
docker-compose.yml

# Ignore Json files
./src/assets/leaflet/region-map.json
./src/assets/leaflet/street-map.json
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ SIMRA_API_URL=localhost:8081/api

MAPILLARY_URL="https://graph.mapillary.com"
MAPILLARY_ACCESS_TOKEN="YOUR TOKEN"

MAP_TILER_TOKEN="YOUR TOKEN"
7 changes: 4 additions & 3 deletions .github/workflows/docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ jobs:
build-args: |
MAPILLARY_URL=${{ vars.MAPILLARY_URL }}
secrets: |
"simra_api_url=${{ secrets.SIMRA_API_URL }}"
"mapillary_access_token=${{ secrets.MAPILLARY_ACCESS_TOKEN }}"
simra_api_url=${{ secrets.SIMRA_API_URL }}
mapillary_access_token=${{ secrets.MAPILLARY_ACCESS_TOKEN }}
map_tiler_token=${{ secrets.MAP_TILER_TOKEN }}
27 changes: 27 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ WORKDIR /usr/src/app
ARG SIMRA_API_URL
ARG MAPILLARY_URL
ARG MAPILLARY_ACCESS_TOKEN
ARG MAP_TILER_TOKEN

ENV SIMRA_API_URL=$SIMRA_API_URL
ENV MAPILLARY_URL=$MAPILLARY_URL
ENV MAPILLARY_ACCESS_TOKEN=$MAPILLARY_ACCESS_TOKEN
ENV MAP_TILER_TOKEN=$MAP_TILER_TOKEN
ENV NX_DAEMON=false

COPY package*.json ./
Expand Down Expand Up @@ -37,8 +39,10 @@ COPY . .

RUN --mount=type=secret,id=simra_api_url \
--mount=type=secret,id=mapillary_access_token \
--mount=type=secret,id=map_tiler_token \
export SIMRA_API_URL=$(cat /run/secrets/simra_api_url) && \
export MAPILLARY_ACCESS_TOKEN=$(cat /run/secrets/mapillary_access_token) && \
export MAP_TILER_TOKEN=$(cat /run/secrets/map_tiler_token) && \
nx build --skip-nx-cache

FROM nginx:stable-alpine AS local_production
Expand All @@ -54,3 +58,26 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=github_builder /usr/src/app/dist/simra/browser /usr/share/nginx/html

EXPOSE 80

FROM node:23-alpine AS local_test

ARG SIMRA_API_URL
ARG MAPILLARY_URL
ARG MAPILLARY_ACCESS_TOKEN
ARG MAP_TILER_TOKEN

ENV SIMRA_API_URL=$SIMRA_API_URL
ENV MAPILLARY_URL=$MAPILLARY_URL
ENV MAPILLARY_ACCESS_TOKEN=$MAPILLARY_ACCESS_TOKEN
ENV MAP_TILER_TOKEN=$MAP_TILER_TOKEN
ENV NX_DAEMON=false

COPY package*.json ./

RUN npm ci --ignore-scripts
RUN npm install -g nx

COPY . .

RUN nx serve
EXPOSE 4200
3 changes: 2 additions & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ services:
SIMRA_API_URL: ${SIMRA_API_URL}
MAPILLARY_URL: ${MAPILLARY_URL}
MAPILLARY_ACCESS_TOKEN: ${MAPILLARY_ACCESS_TOKEN}
MAP_TILER_TOKEN: ${MAP_TILER_TOKEN}
ports:
- "4200:80"
- "4200:4200"
env_file:
- .env
19 changes: 19 additions & 0 deletions k6s/backend-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import http from 'k6/http';
import { sleep, check } from 'k6';

export const options = {
vus: 5,
duration: '40s',
};

export default function () {
let res = http.get('http://konsumpi:8081/api/streets/grid?lat=52.523232122212534&lng=13.47329869&zoom=9&year=2024');
res = http.get('http://konsumpi:8081/api/safety-metrics/simra-regions/Berlin-Potsdam');
res = http.get('http://konsumpi:8081/api/safety-metrics/streets?size=20&minNumberOfRides=2&page=0&weekDay=ALL_WEEK&trafficTime=ALL_DAY&year=2000&sort=dangerousScore,DESC');
// res = http.get('http://konsumpi:8081/api/safety-metrics/regions?size=20&minNumberOfRides=100&page=0&weekDay=ALL_WEEK&trafficTime=ALL_DAY&year=2000&sort=dangerousScore,DESC');

check(res, {
'Status ist 200': (r) => r.status === 200,
'Antwortzeit < 300': (r) => r.timings.duration < 300,
});
}
18 changes: 18 additions & 0 deletions k6s/frontend-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import http from 'k6/http';
import { sleep, check } from 'k6';

export const options = {
vus: 10,
duration: '30s',
};

export default function () {
const res = http.get('https://konsumpi:8081/streets/map?lat=52.522&lng=13.413&zoom=14');

check(res, {
'Status ist 200': (r) => r.status === 200,
'Antwortzeit < 500ms': (r) => r.timings.duration < 500,
});

sleep(1);
}
1 change: 0 additions & 1 deletion libs/common/models/src/lib/enums/year.enum.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export enum EYear {
ALL = '2000',
Y2018 = '2018',
Y2019 = '2019',
Y2020 = '2020',
Y2021 = '2021',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export interface AppEnvironmentInterface extends Environment {
apiUrl: string;
mapillaryUrl: string;
mapillaryAccessToken: string;
mapTilerToken: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,9 @@ export interface IMapPosition extends CoordinateInterface {
* ID of the street
*/
osm_id?: number;

/**
* Indicates if a jump or fly is performed
*/
isNavigated?: boolean;
}
1 change: 1 addition & 0 deletions libs/common/models/src/lib/interfaces/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ export * from './request-page.interface';
export * from './ride.interface';
export * from './safety-metrics.interface';
export * from './safety-metrics-street.interface';
export * from './safety-metrics-region.interface';

Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { ISafetyMetrics } from '@simra/common-models';
import { IRegion } from './region.interface';
import { ISafetyMetrics } from './safety-metrics.interface';

/**
* The safety metrics of a region of osm
*/
export interface ISafetyMetricsRegion extends ISafetyMetrics {
region: IRegion;
name: string;
totalDistance: number;
}
8 changes: 6 additions & 2 deletions libs/common/ui/components/assets/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@
},
"TABLE": {
"ITEMS": {
"SELECTED": "Elemente ausgewählt"
"SELECTED": "Elemente ausgewählt",
"NO_DATA": "Keine Daten"
},
"HEADER": {
"PLACEHOLDER": "Nichts ausgewählt",
"REGION": "Wähle Verwaltungsbezirke aus",
"REGION": "Wähle den Verwaltungsbezirk",
"COLUMNS": {
"ID": "ID",
"OSM_ID": "OSM ID",
Expand Down Expand Up @@ -74,6 +75,9 @@
"LOW_RISK": "Niedriges Risiko",
"HIGH_RISK": "Hohes Risiko"
}
},
"SAFETY_METRICS_DIGIT_PANEL": {
"NO_STREET_SELECTED": "Keine Straßensegment ausgewählt"
}
},
"ORGANISMS": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import { EDangerousColors } from '@simra/common-models';
import type { Meta, StoryObj } from '@storybook/angular';
import { StorybookTranslateModule } from '@simra/helpers';
import { Meta, moduleMetadata, StoryObj } from '@storybook/angular';
import { ColorBlockComponent } from './color-block.component';

const meta: Meta<ColorBlockComponent> = {
component: ColorBlockComponent,
title: 'ColorBlock',
decorators: [
moduleMetadata({
imports: [StorybookTranslateModule]
})
]
};
export default meta;
type Story = StoryObj<ColorBlockComponent>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export class ColorBlockComponent {
/**
* Determines the color of the block
*/
color = input.required<EDangerousColors>(); // Default color
color = input.required<EDangerousColors>();

@HostBinding('style.--color') get hostColor() {
return this.color();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Directive, effect, ElementRef, inject, input, Renderer2 } from '@angular/core';
import { Directive, effect, ElementRef, inject, input, Renderer2, resource } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { TranslateService } from '@ngx-translate/core';
import { firstValueFrom } from 'rxjs';

@Directive({
selector: '[aFallbackValue]',
Expand All @@ -11,15 +13,22 @@ export class FallbackValueDirective {

fallback = input('COMPONENTS.GENERAL.TABLE.ITEMS.NO_DATA');

private readonly langSignal = toSignal(this._translateService.onLangChange);

private readonly _translation$ = resource({
request: () => this.langSignal() ?? this._translateService.currentLang,
loader: async () => {
return await firstValueFrom(this._translateService.get(this.fallback()));
}
});

constructor() {
effect(() => {
const value = this._elementRef.nativeElement.textContent.trim();
if (value) {
return ;
const translated = this._translation$.value();
if (translated) {
this._renderer.setProperty(this._elementRef.nativeElement, 'textContent', translated);
}

const translatedFallback = this._translateService.instant(this.fallback());
this._renderer.setProperty(this._elementRef.nativeElement, 'textContent', translatedFallback);
});

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<h4>{{ "COMPONENTS.GENERAL.GENERAL.LAST_MODIFIED" | translate }}:</h4>
<div class="loading__container">
@if(date(); as lastRun) {
{{ lastRun | date: "dd.MM.yyyy HH:mm":"Europe/Berlin" }}
} @else {
<div class="mt-1">
<p-skeleton class="w-full"></p-skeleton>
</div>
}
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.a-last-run {
@apply flex flex-nowrap opacity-75 gap-4;

.loading__container {
@apply block;

width: 8.25rem;
}

& > * {
@apply text-nowrap;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Component } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core';
import { LastRunComponent } from './last-run.component';

@Component({
selector: 'a-lst-updated-component',
template: '<a-last-run [date]="lastRun"></a-last-run>',
imports: [LastRunComponent],
})
class TestHostComponent {
lastRun = new Date()
}
describe('Integration Test LastRunComponent', () => {
let fixture: ComponentFixture<TestHostComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [TestHostComponent, TranslateModule.forRoot()],
}).compileComponents();

fixture = TestBed.createComponent(TestHostComponent);
fixture.detectChanges();
});

it('should create', () => {
expect(fixture.componentInstance).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, Component, input, ViewEncapsulation } from '@angular/core';
import { TranslatePipe } from '@ngx-translate/core';
import { Skeleton } from 'primeng/skeleton';

@Component({
selector: 'a-last-run',
imports: [CommonModule, Skeleton, TranslatePipe],
templateUrl: './last-run.component.html',
styleUrl: './last-run.component.scss',
host: {
class: 'a-last-run',
},
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
})
export class LastRunComponent {
public date = input.required<Date | undefined>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './component/last-run.component';
1 change: 1 addition & 0 deletions libs/common/ui/components/src/lib/atoms/public-api.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './status-icon/public-api';
export * from './fallback-value/public-api';
export * from './last-run/public-api';
19 changes: 19 additions & 0 deletions libs/common/ui/components/src/lib/models/chart-colors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export class ChartColors {
static SCORE = '#7c86ff';
static INCIDENT_TYPES = [
'#a3c4f3',
'#90dbf4',
'#8eecf5',
'#98f5e1',
'#b9fbc0',
'#cfbaf0',
'#f1c0e8',
'#ffcfd2',
'#fde4cf',
'#fbf8cc',
];
static INCIDENT_TYPES_WITH_SCORE = [ChartColors.SCORE, ...ChartColors.INCIDENT_TYPES];
static RIDE_METRICS_DISTRIBUTION = ['#fef9c2', '#ffd6a7', '#ffc9c9'];
static RIDE_METRICS_DISTRIBUTION_WITH_SCORE = [ChartColors.SCORE, '#ddd6ff', '#e9d4ff', ...ChartColors.RIDE_METRICS_DISTRIBUTION];
static PROFILE_METRICS_DISTRIBUTION_WITH_SCORE = [ChartColors.SCORE, ...ChartColors.RIDE_METRICS_DISTRIBUTION];
}
4 changes: 3 additions & 1 deletion libs/common/ui/components/src/lib/models/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,21 @@ import { ISafetyMetrics } from '@simra/common-models';

export function safetyMetricsDisplayArray<T extends ISafetyMetrics>(
safetyMetrics: T,
): { label: string; data: any }[] {
): { label: string; data: any, link?: string }[] {
const specificAttributes = [];

if ('osmId' in safetyMetrics) {
specificAttributes.push({
label: 'COMPONENTS.GENERAL.TABLE.HEADER.COLUMNS.OSM_ID',
data: safetyMetrics.osmId,
link: `/streets/${safetyMetrics.osmId}`,
});
}
if ('name' in safetyMetrics) {
specificAttributes.push({
label: 'COMPONENTS.GENERAL.TABLE.HEADER.COLUMNS.NAME',
data: safetyMetrics.name,
link: `/administrative-districts/${safetyMetrics.name}`,
});
}

Expand Down
1 change: 1 addition & 0 deletions libs/common/ui/components/src/lib/models/public-api.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './chart-colors';
export * from './const';
export * from './enum-column.interface';
export * from './is-enum-column.function';
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export class AutocompleteComponent {
const field = this.field();
if (!field) return;

this.selectionChange.emit({ [field]: values?.value || '' }); // Emit empty string when cleared
this.selectionChange.emit({ [field]: values?.value || '' });
}

protected async onComplete(event: AutoCompleteCompleteEvent) {
Expand Down
Loading
Loading