Skip to content
Snippets Groups Projects
Commit f6c5c87a authored by OZGCloud's avatar OZGCloud
Browse files

Merge remote-tracking branch 'origin/master' into OZG-3961---ozg-operator

parents 534e2f58 24c317a6
Branches
Tags
No related merge requests found
Showing
with 135 additions and 64 deletions
......@@ -67,6 +67,7 @@ services:
- KEYCLOAK_RESOURCE=${KEYCLOAK_CLIENT:-alfa}
- KEYCLOAK_AUTH_SERVER_URL=https://sso.dev.by.ozg-cloud.de
- OZGCLOUD_USER-ASSISTANCE_DOCUMENTATION_URL=/assets/benutzerleitfaden/Benutzerleitfaden_2.5.pdf
- GOOFY_FEATURES_LOESCHANFORDERUNG=true
ports:
- 8080:8080
depends_on:
......@@ -93,11 +94,10 @@ services:
soft: 65536
hard: 65536
healthcheck:
test: [ "CMD", "curl", "-f", "http://localhost:9200" ]
test: ["CMD-SHELL", "curl -s 'http://localhost:9200/_cat/health?h=status' | egrep -q '(green|yellow)'"]
interval: 10s
timeout: 10s
retries: 5
start_period: 30s
ozg-usermanager:
image: docker.ozg-sh.de/user-manager:${USERMANAGER_DOCKER_IMAGE:-snapshot-latest}
platform: linux/amd64
......
export class HelpMenuE2EComponent {
private readonly rootLocator: string = 'help-menu';
private readonly buttonLocator: string = 'help-menu-button';
public getRoot() {
return cy.getTestElementWithOid(this.rootLocator);
}
public getButton() {
return this.getRoot().getTestElementWithOid(this.buttonLocator);
}
}
......@@ -64,6 +64,12 @@ describe('VorgangList Page', () => {
isKeyboardFocused(vorgangSearch.getClearButton());
})
it('should focus help menu icon', () => {
pressTab();
isKeyboardFocused(header.getHelpMenu().getButton());
})
it('should focus settings icon', () => {
pressTab();
......
......@@ -55,8 +55,5 @@ describe('Buildinfo', () => {
exist(buildInfo.getVersion());
})
it('should show buildTime', () => {
exist(buildInfo.getBuildTime());
})
})
})
\ No newline at end of file
......@@ -6,9 +6,8 @@ import { PostfachMailE2EComponent } from 'apps/goofy-e2e/src/components/postfach
import { UserProfileE2EComponent } from 'apps/goofy-e2e/src/components/user-profile/user-profile.component.e2e';
import { VorgangFormularButtonsE2EComponent } from 'apps/goofy-e2e/src/components/vorgang/vorgang-formular-buttons.e2e.components';
import { WiedervorlageInVorgangE2EComponent } from 'apps/goofy-e2e/src/components/wiedervorlage/wiedervorlage-in-vorgang.e2e.component';
import { WiedervorlageE2EComponent } from 'apps/goofy-e2e/src/components/wiedervorlage/wiedervorlage-page.e2e.component';
import { WiedervorlagePage } from 'apps/goofy-e2e/src/page-objects/wiedervorlage.po';
import { formatDateLocal } from 'apps/goofy-e2e/src/support/tech.util';
import { initVorgangAttachedItem } from 'apps/goofy-e2e/src/support/vorgang-attached-item-util';
import { createWiedervorlageAttachedItem, createWiedervorlageUriByVorgangIdAndWiedervorlageId } from 'apps/goofy-e2e/src/support/wiedervorlage-util';
import { SnackBarE2EComponent } from '../../../components/ui/snackbar.e2e.component';
import { VorgangListE2EComponent } from '../../../components/vorgang/vorgang-list.e2e.component';
import { VorgangE2E, VorgangMessagesE2E, VorgangStatusE2E, vorgangStatusLabelE2E } from '../../../model/vorgang';
......@@ -31,17 +30,16 @@ describe('Vorgang Löschen anfordern', () => {
const vorgangAbgeschlossenLoeschenAnfordern: VorgangE2E = { ...buildVorgang(objectIds[0], 'DoAbgeschlossenLoeschenAnfordern'), status: VorgangStatusE2E.ABGESCHLOSSEN };
const vorgangAbgeschlossenLoeschenAnfordernRevoke: VorgangE2E = { ...buildVorgang(objectIds[1], 'DoAbgeschlossenRevokeLoeschenAnfordern'), status: VorgangStatusE2E.ABGESCHLOSSEN };
const vorgangVerworfenLoeschenAnfordern: VorgangE2E = { ...buildVorgang(objectIds[2], 'DoVerworfenLoeschenAnfordern'), status: VorgangStatusE2E.VERWORFEN };
const vorgangVerworfenLoeschenAnfordernRevoke: VorgangE2E = { ...buildVorgang(objectIds[3], 'DoVerworfenRevokeLoeschenAnfordern'), status: VorgangStatusE2E.VERWORFEN };
const wiedervorlagePage: WiedervorlagePage = new WiedervorlagePage();
const wiedervorlageContainer: WiedervorlageE2EComponent = wiedervorlagePage.getWiedervorlageContainer();
const wiedervorlageBetreff: string = 'TestWiedervorlage';
const wiedervorlageBeschreibung: string = 'Beschreibung einer Wiedervorlage';
const wiedervorlageFrist: string = formatDateLocal(new Date(), 'dd.MM.yyyy');
const wiedervorlageAttachedItem = createWiedervorlageAttachedItem(objectIds[4], vorgangAbgeschlossenLoeschenAnfordern._id.$oid);
const wiedervorlageUrl = createWiedervorlageUriByVorgangIdAndWiedervorlageId(objectIds[0], objectIds[4]);
before(() => {
initVorgaenge([vorgangAbgeschlossenLoeschenAnfordern, vorgangAbgeschlossenLoeschenAnfordernRevoke, vorgangVerworfenLoeschenAnfordern, vorgangVerworfenLoeschenAnfordernRevoke]);
initVorgangAttachedItem([wiedervorlageAttachedItem]);
loginAsSabine();
......@@ -64,24 +62,6 @@ describe('Vorgang Löschen anfordern', () => {
describe('by button', () => {
it('should create Wiedervorlage', () => {
vorgangPage.getWiedervorlagenContainer().getCreateWiedervorlageButton().click();
waitForSpinnerToDisappear();
exist(wiedervorlagePage.getSubnavigation().getRoot());
wiedervorlageContainer.getBetreff().clear().type(wiedervorlageBetreff);
wiedervorlageContainer.getBeschreibung().clear().type(wiedervorlageBeschreibung);
wiedervorlageContainer.getFrist().clear().type(wiedervorlageFrist);
wiedervorlageContainer.getSpeichernButton().click();
waitForSpinnerToDisappear();
const wiedervorlageInVorgang: WiedervorlageInVorgangE2EComponent = vorgangPage.getWiedervorlagenContainer().getWiedervorlage(wiedervorlageBetreff);
exist(wiedervorlageInVorgang.getLink());
})
it('should have status Abgeschlossen', () => {
haveText(vorgangPage.getVorgangDetailHeader().getStatus(), vorgangStatusLabelE2E[vorgangAbgeschlossenLoeschenAnfordern.status]);
})
......@@ -106,6 +86,23 @@ describe('Vorgang Löschen anfordern', () => {
haveText(vorgangPage.getVorgangDetailHeader().getStatus(), vorgangStatusLabelE2E[VorgangStatusE2E.ZU_LOESCHEN]);
})
it('should redirect Wiedervorlage link to Vorgang', () => {
cy.visit(wiedervorlageUrl);
exist(vorgangPage.getVorgangDetailHeader().getRoot());
})
it('should show snackBar message', () => {
exist(snackBar.getCloseButton());
contains(snackBar.getMessage(), VorgangMessagesE2E.WIEDERVORLAGE_BEARBEITEN_NICHT_MOEGLICH)
})
it('should close snackBar', () => {
snackBar.getCloseButton().click();
notExist(snackBar.getMessage());
})
it('back to vorgang list', () => {
vorgangPage.getSubnavigation().clickBackButton();
waitForSpinnerToDisappear();
......@@ -154,7 +151,7 @@ describe('Vorgang Löschen anfordern', () => {
})
it('should disable open Wiedervorlage-Page link ', () => {
const wiedervorlageInVorgang: WiedervorlageInVorgangE2EComponent = vorgangPage.getWiedervorlagenContainer().getWiedervorlage(wiedervorlageBetreff);
const wiedervorlageInVorgang: WiedervorlageInVorgangE2EComponent = vorgangPage.getWiedervorlagenContainer().getWiedervorlage('Wiedervorlage');
notExist(wiedervorlageInVorgang.getLink());
})
......
......@@ -152,7 +152,8 @@ export enum VorgangMessagesE2E {
ABGESCHLOSSEN = 'Der Vorgang wurde abgeschlossen.',
WIEDEREROEFFNET = 'Der Vorgang wurde wiedereröffnet.',
LOESCHEN_ANFORDERN = 'Für den Vorgang wurde eine Löschanforderung gestellt.',
ENDGUELTIG_LOESCHEN = 'Der Vorgang wurde gelöscht.'
ENDGUELTIG_LOESCHEN = 'Der Vorgang wurde gelöscht.',
WIEDERVORLAGE_BEARBEITEN_NICHT_MOEGLICH = 'Im Status "Zu löschen" ist die Bearbeitung von Wiedervorlagen nicht möglich.'
}
export const NO_AKTENZEICHEN: string = 'kein Aktenzeichen zugewiesen';
\ No newline at end of file
......@@ -21,15 +21,17 @@
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
import { CurrentUserProfileE2EComponent } from "../components/user-profile/current-user-profile.component.e2e";
import { UserSettingsE2EComponent } from "../components/user-settings/user-settings.component.e2e";
import { VorgangSearchE2EComponent } from "../components/vorgang/vorgang-search.e2e.component";
import { HelpMenuE2EComponent } from '../components/user-assistance/help-menu.component.e2e';
import { CurrentUserProfileE2EComponent } from '../components/user-profile/current-user-profile.component.e2e';
import { UserSettingsE2EComponent } from '../components/user-settings/user-settings.component.e2e';
import { VorgangSearchE2EComponent } from '../components/vorgang/vorgang-search.e2e.component';
export class HeaderE2EComponent {
private readonly locatorLogo: string = 'alfa-logo';
private readonly locatorRoot: string = 'header';
private readonly helpMenu: HelpMenuE2EComponent = new HelpMenuE2EComponent();
private readonly userSettings: UserSettingsE2EComponent = new UserSettingsE2EComponent();
private readonly currentUserProfile: CurrentUserProfileE2EComponent = new CurrentUserProfileE2EComponent();
private readonly vorgangSearch: VorgangSearchE2EComponent = new VorgangSearchE2EComponent();
......@@ -46,6 +48,10 @@ export class HeaderE2EComponent {
return this.vorgangSearch;
}
public getHelpMenu(): HelpMenuE2EComponent {
return this.helpMenu;
}
public getUserSettings(): UserSettingsE2EComponent {
return this.userSettings;
}
......
......@@ -27,6 +27,7 @@ import { WiedervorlageE2E } from '../model/wiedervorlage';
import { buildUrl } from './tech.util';
import { getUserSabineInternalId } from './user-util';
import { VORGANG_ATTACHED_ITEM_CLASS } from './vorgang-attached-item-util';
import { createVorgangUriById } from './vorgang-util';
/** @deprecated */
const wiedervorlageFixture: WiedervorlageE2E = require('../fixtures/wiedervorlage/wiedervorlage.json');
......@@ -46,7 +47,11 @@ export function buildWiedervorlage(_id: string, uiIdentifier: string): Wiedervor
}
export function createWiedervorlageNeuUriByVorgangId(id: string): string {
return `/vorgang/${encodeUrlForEmbedding(buildUrl(id, 'vorgangs'))}/wiedervorlage/neu`;
return `${createVorgangUriById(id)}/wiedervorlage/neu`;
}
export function createWiedervorlageUriByVorgangIdAndWiedervorlageId(vorgangId: string, wiedervorlageId: string): string {
return `${createVorgangUriById(vorgangId)}/wiedervorlage/${encodeUrlForEmbedding(buildUrl(wiedervorlageId, 'wiedervorlages'))}`;
}
const wiedervorlageItemFixture: WiedervorlageE2E = require('../fixtures/wiedervorlage/wiedervorlage.json');
......
......@@ -35,27 +35,48 @@ fi
echo "Using docker-compose -f ${SCRIPT_DIR}/docker-compose.yml ..."
echo
if [ "$(expr substr $(uname -s) 1 5)" == "Linux" ];
if [[ "$OSTYPE" == "linux-gnu"* ]]
then
export DOCKER_GATEWAY_HOST=172.17.0.1
fi
docker compose -f ${SCRIPT_DIR}/docker-compose.yml up -d ozg-mongodb ozg-usermanager ozg-elastic
docker compose -f ${SCRIPT_DIR}/docker-compose.yml up -d ozg-mongodb ozg-usermanager ozg-elastic --wait
echo
echo "Starting Pluto to init search index."
SPRING_PROFILE=dev,e2e,initSearchIndex docker compose -f ${SCRIPT_DIR}/docker-compose.yml up -d ozg-pluto
echo
while [[ $(curl -sw '%{http_code}' "http://localhost:9200" | grep -c 200) != 1 ]]
waitForInitSearchIndex() {
(docker compose -f ${SCRIPT_DIR}/docker-compose.yml logs | fgrep -q 'Successful filled up index - exiting')
}
echo "Waiting for Pluto to finish search index initialisation."
until waitForInitSearchIndex
do
echo "Waiting for search service coming up..."
sleep 3
echo -n "."
sleep 1
done
echo
echo "Starting Pluto to init search index..."
SPRING_PROFILE=dev,e2e,initSearchIndex docker compose -f ${SCRIPT_DIR}/docker-compose.yml up ozg-pluto
echo
echo "Starting Pluto and Goofy for normal operations..."
echo "Starting Pluto and Alfa Server for normal operations."
SPRING_PROFILE=dev,e2e docker compose -f ${SCRIPT_DIR}/docker-compose.yml up -d ozg-pluto ozg-goofy ozg-usermanager
waitForServerStarted() {
(docker compose -f ${SCRIPT_DIR}/docker-compose.yml logs | awk 'BEGIN{RS="\0"} /Started AlfaServerApplication/ && /Started PlutoServerApplication/ { exit 1 }')
}
echo
echo "Waiting for Pluto and Alfa Server to log successful start."
while waitForServerStarted
do
echo -n "."
sleep 1
done
echo
echo
echo "Checking Docker Log for \"Started\" lines..."
docker compose -f ${SCRIPT_DIR}/docker-compose.yml logs -f | egrep "(Starting|Started)"
echo "done."
\ No newline at end of file
......@@ -31,7 +31,7 @@
<goofy-client-vorgang-search-container></goofy-client-vorgang-search-container>
</div>
<div class="right">
<goofy-client-help-menu [apiRootStateResource]="apiRootStateResource"></goofy-client-help-menu>
<goofy-client-help-menu [apiRootStateResource]="apiRootStateResource" data-test-id="help-menu"></goofy-client-help-menu>
<goofy-client-user-settings-container data-test-id="user-settings"></goofy-client-user-settings-container>
<goofy-client-user-profile-in-header-container data-test-id="current-user"></goofy-client-user-profile-in-header-container>
</div>
......
......@@ -30,7 +30,7 @@ import { createVorgangListResource } from 'libs/vorgang-shared/test/vorgang';
import { of } from 'rxjs';
import { VorgangFacade } from './+state/vorgang.facade';
import { VorgangListService } from './vorgang-list.service';
import { VorgangFilter, VorgangListResource, VorgangView } from './vorgang.model';
import { VorgangFilter, VorgangListResource, VorgangStatistic, VorgangView } from './vorgang.model';
import * as VorgangNavigationUtil from './vorgang-navigation.util';
......@@ -197,12 +197,25 @@ describe('VorgangListService', () => {
})
describe('getVorgangStatistic', () => {
const vorgangStatisticStateResource: StateResource<VorgangStatistic> = createStateResource(<VorgangStatistic>{});
beforeEach(() => {
vorgangFacade.getVorgangStatistic.mockReturnValue(of(vorgangStatisticStateResource));
service.getVorgangList = jest.fn().mockReturnValue(of(<StateResource<VorgangListResource>>{}));
})
it('should call facade', () => {
service.getVorgangStatistic();
expect(vorgangFacade.getVorgangStatistic).toHaveBeenCalled();
})
it('should getVorgangList', (done) => {
service.getVorgangStatistic().subscribe(() => {
expect(service.getVorgangList).toHaveBeenCalled();
done();
})
})
})
describe('getSelectedFilterAsRouteParam', () => {
......
......@@ -23,9 +23,9 @@
*/
import { Injectable } from '@angular/core';
import { ApiRootFacade, ApiRootResource } from '@goofy-client/api-root-shared';
import { EMPTY_STRING, StateResource, createEmptyStateResource, doIfLoadingRequired, isNotNull } from '@goofy-client/tech-shared';
import { EMPTY_STRING, StateResource, createEmptyStateResource, doIfLoadingRequired, isLoaded, isNotNull } from '@goofy-client/tech-shared';
import { Observable, combineLatest } from 'rxjs';
import { map, startWith, tap, withLatestFrom } from 'rxjs/operators';
import { filter, map, startWith, tap, withLatestFrom } from 'rxjs/operators';
import { VorgangFacade } from './+state/vorgang.facade';
import { ROUTE_PARAM_BY_VORGANG_FILTER, buildLinkRel, getSearchLinkRel } from './vorgang-navigation.util';
import { VorgangFilter, VorgangListResource, VorgangResource, VorgangStatistic, VorgangView } from './vorgang.model';
......@@ -64,7 +64,11 @@ export class VorgangListService {
}
public getVorgangStatistic(): Observable<StateResource<VorgangStatistic>> {
return this.vorgangFacade.getVorgangStatistic();
return this.vorgangFacade.getVorgangStatistic().pipe(
withLatestFrom(this.getVorgangList()),
filter(([, vorgangListResource]) => isLoaded(vorgangListResource)),
map(([statistic,]) => statistic),
);
}
public getSelectedFilterAsRouteParam(): Observable<string> {
......
......@@ -58,6 +58,14 @@ describe('Vorgang Navigation Util', () => {
expect(result).toBe(searchString);
})
it('should return empty string', () => {
const searchString: string = EMPTY_STRING;
const result = getSearchString(buildCurrentRouteData(searchString));
expect(result).toBe(EMPTY_STRING);
})
function buildCurrentRouteData(searchString: string): RouteData {
const urlSegments: UrlSegment[] = [<any>{ path: ALLE_ROUTE_PARAM}, <any>{ path: SEARCH_ROUTE_PARAM}, <any>{ path: searchString }];
const queryParameter = { [SEARCH_ROUTE_PARAM]: searchString };
......
......@@ -25,7 +25,7 @@ import { ApiRootLinkRel } from '@goofy-client/api-root-shared';
import { getFilterFromLocalStorage, getViewFromLocalStorage } from '@goofy-client/app-shared';
import { RouteData } from '@goofy-client/navigation-shared';
import { EMPTY_STRING, isNotEmpty, isNotNull, isNotUndefined } from '@goofy-client/tech-shared';
import { isEmpty } from 'lodash-es';
import { isEmpty, isUndefined } from 'lodash-es';
import { VorgangState } from './+state/vorgang.reducer';
import { VorgangFilter, VorgangView } from './vorgang.model';
......@@ -92,10 +92,7 @@ const SEARCH_LINK_BY_VORGANG_FILTER: { [filter: string]: string } = {
export function getSearchString(routeData: RouteData): string {
const searchString: string = VorgangNavigationUtil.getRouteUrlSegment(routeData, 2);
if (isNotUndefined(searchString)) {
return decodeURIComponent(searchString);
}
return searchString;
return isUndefined(searchString) ? EMPTY_STRING : decodeURIComponent(searchString);
}
export function getSearchLinkRel(vorgangFilter: VorgangFilter): string {
......
......@@ -23,7 +23,7 @@
unter der Lizenz sind dem Lizenztext zu entnehmen.
-->
<ng-container *ngIf="vorgangStatisticStateResource.resource as statistic">
<ng-container *ngIf="vorgangStatisticStateResource?.resource as statistic">
<div class="views">
<goofy-client-vorgang-view-item-container *ngIf="apiRootResource | hasAnyLink: apiRootLinkRel.ALLE_VORGAENGE_NEU: apiRootLinkRel.MEINE_VORGAENGE_NEU: apiRootLinkRel.UNASSIGNED_NEU" data-test-id="vorgang-neu-view"
label="Neu" [view]="vorgangView.NEU" [count]="statistic.byStatus.neu">
......
......@@ -79,7 +79,8 @@ const routes: Routes = [
},
{
path: 'alle/search',
redirectTo: 'alle'
canActivate: [vorgangFilterViewGuard],
component: VorgangListSearchContainerComponent,
},
{
path: 'alle/:status',
......@@ -107,7 +108,8 @@ const routes: Routes = [
},
{
path: 'meine/search',
redirectTo: 'meine'
canActivate: [vorgangFilterViewGuard],
component: VorgangListSearchContainerComponent,
},
{
path: 'meine/:status',
......@@ -135,7 +137,8 @@ const routes: Routes = [
},
{
path: 'unassigned/search',
redirectTo: 'unassigned'
canActivate: [vorgangFilterViewGuard],
component: VorgangListSearchContainerComponent,
},
{
path: 'unassigned/:status',
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment