mirror of
https://github.com/zitadel/zitadel.git
synced 2025-03-01 01:07:23 +00:00
feat: add time range events filter (#7005)
* feat(console): add time range events filter * deprecate creation_date, use oneof filter * use range or from * implement api * fix timestamp format * translate * styles * lint * integration tests * fix until date * rearrange sorting control * sort creation date * fix events e2e test * Update console/src/app/modules/filter-events/filter-events.component.html Co-authored-by: Max Peintner <max@caos.ch> * Update console/src/app/modules/filter-events/filter-events.component.html Co-authored-by: Max Peintner <max@caos.ch> * Update console/src/app/modules/filter-events/filter-events.component.html Co-authored-by: Max Peintner <max@caos.ch> * lint * lint * don't use utc call time --------- Co-authored-by: Max Peintner <max@caos.ch> Co-authored-by: Silvan <silvan.reusser@gmail.com>
This commit is contained in:
parent
2e505f40f9
commit
9da4abd459
@ -145,7 +145,6 @@
|
|||||||
</cnsl-form-field>
|
</cnsl-form-field>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="filter-events-section">
|
<div class="filter-events-section">
|
||||||
<div class="checkbox-wrapper">
|
<div class="checkbox-wrapper">
|
||||||
<mat-checkbox id="sequenceFilterSet" name="sequenceFilterSet" class="cb" formControlName="sequenceFilterSet"
|
<mat-checkbox id="sequenceFilterSet" name="sequenceFilterSet" class="cb" formControlName="sequenceFilterSet"
|
||||||
@ -153,46 +152,73 @@
|
|||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
</div>
|
</div>
|
||||||
<div class="filter-events-sub" *ngIf="sequenceFilterSet?.value">
|
<div class="filter-events-sub" *ngIf="sequenceFilterSet?.value">
|
||||||
<cnsl-form-field class="aggregate-type-select">
|
|
||||||
<cnsl-label>{{ 'IAM.EVENTS.FILTERS.SEQUENCE.SORT' | translate }}</cnsl-label>
|
|
||||||
|
|
||||||
<mat-select id="isAsc" name="isAsc" formControlName="isAsc">
|
|
||||||
<mat-option [value]="false"> {{ 'IAM.EVENTS.FILTERS.SEQUENCE.DESC' | translate }} </mat-option>
|
|
||||||
<mat-option [value]="true">{{ 'IAM.EVENTS.FILTERS.SEQUENCE.ASC' | translate }} </mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</cnsl-form-field>
|
|
||||||
|
|
||||||
<cnsl-form-field class="filter-input-value">
|
<cnsl-form-field class="filter-input-value">
|
||||||
<cnsl-label>{{ 'IAM.EVENTS.FILTERS.SEQUENCE.LABEL' | translate }}</cnsl-label>
|
<cnsl-label>{{ 'IAM.EVENTS.FILTERS.SEQUENCE.LABEL' | translate }}</cnsl-label>
|
||||||
<input cnslInput id="sequence" name="sequence" formControlName="sequence" />
|
<input cnslInput id="sequence" name="sequence" formControlName="sequence" />
|
||||||
</cnsl-form-field>
|
</cnsl-form-field>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="filter-events-section">
|
<div class="filter-events-section">
|
||||||
<div class="checkbox-wrapper">
|
<mat-radio-group aria-label="Select an option" class="filter-events-sub" formControlName="creationDateFilterType">
|
||||||
<mat-checkbox
|
<mat-radio-button [value]="CreationDateFilterType.FROM">
|
||||||
id="creationDateFilterSet"
|
{{ 'IAM.EVENTS.FILTERS.CREATIONDATE.RADIO_FROM' | translate }}
|
||||||
name="creationDateFilterSet"
|
</mat-radio-button>
|
||||||
class="cb"
|
<mat-radio-button [value]="CreationDateFilterType.RANGE">
|
||||||
formControlName="creationDateFilterSet"
|
{{ 'IAM.EVENTS.FILTERS.CREATIONDATE.RADIO_RANGE' | translate }}
|
||||||
>{{ 'IAM.EVENTS.FILTERS.CREATIONDATE.CHECKBOX' | translate }}
|
</mat-radio-button>
|
||||||
</mat-checkbox>
|
</mat-radio-group>
|
||||||
</div>
|
<div class="filter-events-sub">
|
||||||
<div class="filter-events-sub" *ngIf="creationDateFilterSet?.value">
|
<ng-container *ngIf="creationDateFilterType!.value === CreationDateFilterType.FROM">
|
||||||
<cnsl-form-field class="filter-input-value">
|
<mat-form-field class="datetime-input">
|
||||||
<cnsl-label>{{ 'IAM.EVENTS.FILTERS.CREATIONDATE.LABEL' | translate }}</cnsl-label>
|
|
||||||
<input
|
<input
|
||||||
cnslInput
|
class="datetime"
|
||||||
id="creationDate"
|
matInput
|
||||||
name="creationDate"
|
type="datetime-local"
|
||||||
[matDatepicker]="picker"
|
name="creationDateFrom"
|
||||||
formControlName="creationDate"
|
[value]="creationDateFrom!.value | date: 'yyyy-MM-dd HH:mm:ss'"
|
||||||
|
(change)="creationDateFrom = $event.target"
|
||||||
/>
|
/>
|
||||||
<mat-datepicker-toggle style="top: 0" cnslSuffix [for]="picker"></mat-datepicker-toggle>
|
</mat-form-field>
|
||||||
<mat-datepicker #picker></mat-datepicker>
|
</ng-container>
|
||||||
</cnsl-form-field>
|
<ng-container *ngIf="creationDateFilterType!.value === CreationDateFilterType.RANGE">
|
||||||
|
<div class="datetime-range">
|
||||||
|
<mat-form-field class="datetime-input">
|
||||||
|
<cnsl-label
|
||||||
|
>{{ 'IAM.EVENTS.FILTERS.CREATIONDATE.LABEL_SINCE' | translate }}
|
||||||
|
<input
|
||||||
|
matInput
|
||||||
|
type="datetime-local"
|
||||||
|
name="creationDateSince"
|
||||||
|
[value]="creationDateSince!.value | date: 'yyyy-MM-dd HH:mm:ss'"
|
||||||
|
(change)="creationDateSince = $event.target"
|
||||||
|
/>
|
||||||
|
</cnsl-label>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="datetime-input">
|
||||||
|
<cnsl-label
|
||||||
|
>{{ 'IAM.EVENTS.FILTERS.CREATIONDATE.LABEL_UNTIL' | translate }}
|
||||||
|
<input
|
||||||
|
matInput
|
||||||
|
type="datetime-local"
|
||||||
|
name="creationDateUntil"
|
||||||
|
[value]="creationDateUntil!.value | date: 'yyyy-MM-dd HH:mm:ss'"
|
||||||
|
(change)="creationDateUntil = $event.target"
|
||||||
|
/>
|
||||||
|
</cnsl-label>
|
||||||
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="filter-events-section">
|
||||||
|
<cnsl-form-field class="aggregate-type-select">
|
||||||
|
<cnsl-label>{{ 'IAM.EVENTS.FILTERS.SORT' | translate }}</cnsl-label>
|
||||||
|
|
||||||
|
<mat-select id="isAsc" name="isAsc" formControlName="isAsc">
|
||||||
|
<mat-option [value]="false"> {{ 'IAM.EVENTS.FILTERS.DESC' | translate }} </mat-option>
|
||||||
|
<mat-option [value]="true">{{ 'IAM.EVENTS.FILTERS.ASC' | translate }} </mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</cnsl-form-field>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 0.5rem 0;
|
padding: 0.5rem 0;
|
||||||
min-width: 320px;
|
min-width: 360px;
|
||||||
max-width: 360px;
|
max-width: 360px;
|
||||||
padding-bottom: 0.5rem;
|
padding-bottom: 0.5rem;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -55,11 +55,23 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mdc-text-field--filled:not(.mdc-text-field--disabled) {
|
||||||
|
background-color: map-get($background, cards);
|
||||||
|
}
|
||||||
|
|
||||||
|
.datetime-input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.datetime-range {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
.filter-events-sub {
|
.filter-events-sub {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-around;
|
||||||
padding: 0 0.5rem;
|
padding: 0 0.5rem;
|
||||||
background-color: if($is-dark-theme, #00000020, #00000008);
|
background-color: if($is-dark-theme, #00000020, #00000008);
|
||||||
margin: 0 -0.5rem;
|
margin: 0 -0.5rem;
|
||||||
|
@ -15,13 +15,18 @@ export enum UserTarget {
|
|||||||
EXTERNAL = 'external',
|
EXTERNAL = 'external',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum CreationDateFilterType {
|
||||||
|
FROM = 'from',
|
||||||
|
RANGE = 'range',
|
||||||
|
}
|
||||||
|
|
||||||
function dateToTs(date: Date): Timestamp {
|
function dateToTs(date: Date): Timestamp {
|
||||||
const ts = new Timestamp();
|
const ts = new Timestamp();
|
||||||
const milliseconds = date.getTime();
|
const milliseconds = date.getTime();
|
||||||
const seconds = Math.abs(milliseconds / 1000);
|
const seconds = milliseconds / 1000;
|
||||||
const nanos = (milliseconds - seconds * 1000) * 1000 * 1000;
|
const nanos = (milliseconds - seconds * 1000) * 1000 * 1000;
|
||||||
ts.setSeconds(seconds);
|
ts.setSeconds(Math.round(seconds));
|
||||||
ts.setNanos(nanos);
|
ts.setNanos(Math.round(nanos));
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,6 +36,9 @@ function dateToTs(date: Date): Timestamp {
|
|||||||
styleUrls: ['./filter-events.component.scss'],
|
styleUrls: ['./filter-events.component.scss'],
|
||||||
})
|
})
|
||||||
export class FilterEventsComponent implements OnInit {
|
export class FilterEventsComponent implements OnInit {
|
||||||
|
// Make enum available in template
|
||||||
|
public CreationDateFilterType = CreationDateFilterType;
|
||||||
|
|
||||||
public showFilter: boolean = false;
|
public showFilter: boolean = false;
|
||||||
public ActionKeysType: any = ActionKeysType;
|
public ActionKeysType: any = ActionKeysType;
|
||||||
|
|
||||||
@ -53,8 +61,11 @@ export class FilterEventsComponent implements OnInit {
|
|||||||
sequenceFilterSet: new FormControl(false),
|
sequenceFilterSet: new FormControl(false),
|
||||||
sequence: new FormControl(''),
|
sequence: new FormControl(''),
|
||||||
isAsc: new FormControl<boolean>(false),
|
isAsc: new FormControl<boolean>(false),
|
||||||
creationDateFilterSet: new FormControl(false),
|
creationDateFilterType: new FormControl(CreationDateFilterType.FROM),
|
||||||
creationDate: new FormControl<Date>(new Date()),
|
creationDateFrom: new FormControl<Date>(new Date()),
|
||||||
|
// creationDateSince is 15 minutes in the past by default
|
||||||
|
creationDateSince: new FormControl<Date>(new Date(new Date().getTime() - 15 * 60_000)),
|
||||||
|
creationDateUntil: new FormControl<Date>(new Date()),
|
||||||
userFilterSet: new FormControl(false),
|
userFilterSet: new FormControl(false),
|
||||||
editorUserId: new FormControl(''),
|
editorUserId: new FormControl(''),
|
||||||
aggregateFilterSet: new FormControl(false),
|
aggregateFilterSet: new FormControl(false),
|
||||||
@ -78,20 +89,35 @@ export class FilterEventsComponent implements OnInit {
|
|||||||
const { filter } = params;
|
const { filter } = params;
|
||||||
if (filter) {
|
if (filter) {
|
||||||
const stringifiedFilters = filter as string;
|
const stringifiedFilters = filter as string;
|
||||||
const filters = JSON.parse(stringifiedFilters);
|
const filters = JSON.parse(decodeURIComponent(stringifiedFilters));
|
||||||
|
|
||||||
if (filters.aggregateId) {
|
if (filters.aggregateId) {
|
||||||
this.request.setAggregateId(filters.aggregateId);
|
this.request.setAggregateId(filters.aggregateId);
|
||||||
this.aggregateId?.setValue(filters.aggregateId);
|
this.aggregateId?.setValue(filters.aggregateId);
|
||||||
this.aggregateFilterSet?.setValue(true);
|
this.aggregateFilterSet?.setValue(true);
|
||||||
}
|
}
|
||||||
if (filters.creationDate) {
|
if (filters.creationDateFrom) {
|
||||||
const milliseconds = filters.creationDate;
|
const millisecondsFrom = filters.creationDateFrom;
|
||||||
const date = new Date(milliseconds);
|
const dateFrom = new Date(millisecondsFrom);
|
||||||
const ts = dateToTs(date);
|
const ts = dateToTs(dateFrom);
|
||||||
|
this.creationDateFrom?.setValue(dateFrom);
|
||||||
|
this.creationDateFilterType?.setValue(CreationDateFilterType.FROM);
|
||||||
this.request.setCreationDate(ts);
|
this.request.setCreationDate(ts);
|
||||||
this.creationDate?.setValue(date);
|
}
|
||||||
this.creationDateFilterSet?.setValue(true);
|
if (filters.creationDateSince || filters.creationDateUntil) {
|
||||||
|
const millisecondsFrom = filters.creationDateSince;
|
||||||
|
const dateSince = new Date(millisecondsFrom);
|
||||||
|
const tsSince = dateToTs(dateSince);
|
||||||
|
this.creationDateSince?.setValue(dateSince);
|
||||||
|
const millisecondsUntil = filters.creationDateUntil;
|
||||||
|
const dateUntil = new Date(millisecondsUntil);
|
||||||
|
const tsUntil = dateToTs(dateUntil);
|
||||||
|
this.creationDateUntil?.setValue(dateUntil);
|
||||||
|
const range = new ListEventsRequest.creation_date_range();
|
||||||
|
range.setSince(tsSince);
|
||||||
|
range.setUntil(tsUntil);
|
||||||
|
this.request.setRange(range);
|
||||||
|
this.creationDateFilterType?.setValue(CreationDateFilterType.RANGE);
|
||||||
}
|
}
|
||||||
if (filters.aggregateTypesList && filters.aggregateTypesList.length) {
|
if (filters.aggregateTypesList && filters.aggregateTypesList.length) {
|
||||||
const values = this.aggregateTypes.filter((agg) => filters.aggregateTypesList.includes(agg.type));
|
const values = this.aggregateTypes.filter((agg) => filters.aggregateTypesList.includes(agg.type));
|
||||||
@ -252,11 +278,28 @@ export class FilterEventsComponent implements OnInit {
|
|||||||
constructRequest.setAsc(formValues.isAsc);
|
constructRequest.setAsc(formValues.isAsc);
|
||||||
filterObject.isAsc = formValues.isAsc;
|
filterObject.isAsc = formValues.isAsc;
|
||||||
}
|
}
|
||||||
if (formValues.creationDateFilterSet && formValues.creationDate) {
|
if (formValues.creationDateFilterType === CreationDateFilterType.FROM) {
|
||||||
const date = new Date(formValues.creationDate);
|
const dateFrom = new Date(formValues.creationDateFrom);
|
||||||
const ts = dateToTs(date);
|
const tsFrom = dateToTs(dateFrom);
|
||||||
constructRequest.setCreationDate(ts);
|
constructRequest.setFrom(tsFrom);
|
||||||
filterObject.creationDate = date.getTime();
|
constructRequest.clearRange();
|
||||||
|
filterObject.creationDateFrom = dateFrom.getTime();
|
||||||
|
filterObject.creationDateSince = undefined;
|
||||||
|
filterObject.creationDateUntil = undefined;
|
||||||
|
}
|
||||||
|
if (formValues.creationDateFilterType === CreationDateFilterType.RANGE) {
|
||||||
|
const range = new ListEventsRequest.creation_date_range();
|
||||||
|
const dateSince = new Date(formValues.creationDateSince);
|
||||||
|
const tsSince = dateToTs(dateSince);
|
||||||
|
range.setSince(tsSince);
|
||||||
|
filterObject.creationDateSince = dateSince.getTime();
|
||||||
|
const dateUntil = new Date(formValues.creationDateUntil);
|
||||||
|
const tsUntil = dateToTs(dateUntil);
|
||||||
|
range.setUntil(tsUntil);
|
||||||
|
filterObject.creationDateUntil = dateUntil.getTime();
|
||||||
|
constructRequest.setRange(range);
|
||||||
|
constructRequest.clearFrom();
|
||||||
|
filterObject.creationDateFrom = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.requestChanged.emit(constructRequest);
|
this.requestChanged.emit(constructRequest);
|
||||||
@ -265,7 +308,7 @@ export class FilterEventsComponent implements OnInit {
|
|||||||
this.router.navigate([], {
|
this.router.navigate([], {
|
||||||
relativeTo: this.route,
|
relativeTo: this.route,
|
||||||
queryParams: {
|
queryParams: {
|
||||||
['filter']: JSON.stringify(filterObject),
|
['filter']: encodeURIComponent(JSON.stringify(filterObject)),
|
||||||
},
|
},
|
||||||
replaceUrl: true,
|
replaceUrl: true,
|
||||||
queryParamsHandling: 'merge',
|
queryParamsHandling: 'merge',
|
||||||
@ -304,12 +347,32 @@ export class FilterEventsComponent implements OnInit {
|
|||||||
return this.form.get('sequenceFilterSet');
|
return this.form.get('sequenceFilterSet');
|
||||||
}
|
}
|
||||||
|
|
||||||
public get creationDate(): AbstractControl | null {
|
public get creationDateFilterType(): AbstractControl | null {
|
||||||
return this.form.get('creationDate');
|
return this.form.get('creationDateFilterType');
|
||||||
}
|
}
|
||||||
|
|
||||||
public get creationDateFilterSet(): AbstractControl | null {
|
public get creationDateFrom(): AbstractControl | null {
|
||||||
return this.form.get('creationDateFilterSet');
|
return this.form.get('creationDateFrom');
|
||||||
|
}
|
||||||
|
|
||||||
|
public set creationDateFrom(event: EventTarget | null) {
|
||||||
|
this.setDate(this.creationDateFrom!, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get creationDateSince(): AbstractControl | null {
|
||||||
|
return this.form.get('creationDateSince');
|
||||||
|
}
|
||||||
|
|
||||||
|
public set creationDateSince(event: EventTarget | null) {
|
||||||
|
this.setDate(this.creationDateSince!, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get creationDateUntil(): AbstractControl | null {
|
||||||
|
return this.form.get('creationDateUntil');
|
||||||
|
}
|
||||||
|
|
||||||
|
public set creationDateUntil(event: EventTarget | null) {
|
||||||
|
this.setDate(this.creationDateUntil!, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get resourceOwnerFilterSet(): AbstractControl | null {
|
public get resourceOwnerFilterSet(): AbstractControl | null {
|
||||||
@ -341,9 +404,6 @@ export class FilterEventsComponent implements OnInit {
|
|||||||
if (this.userFilterSet?.value && this.editorUserId?.value) {
|
if (this.userFilterSet?.value && this.editorUserId?.value) {
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
if (this.creationDateFilterSet?.value && this.creationDate?.value) {
|
|
||||||
++count;
|
|
||||||
}
|
|
||||||
if (this.aggregateFilterSet?.value && this.aggregateId?.value) {
|
if (this.aggregateFilterSet?.value && this.aggregateId?.value) {
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
@ -361,4 +421,11 @@ export class FilterEventsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private setDate(ctrl: AbstractControl<Date>, event: EventTarget | null): void {
|
||||||
|
if (!(event instanceof HTMLInputElement)) {
|
||||||
|
throw new Error('wrong target');
|
||||||
|
}
|
||||||
|
ctrl.setValue(new Date(event.value || ''));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|||||||
import { ActionKeysModule } from '../action-keys/action-keys.module';
|
import { ActionKeysModule } from '../action-keys/action-keys.module';
|
||||||
import { InputModule } from '../input/input.module';
|
import { InputModule } from '../input/input.module';
|
||||||
import { FilterEventsComponent } from './filter-events.component';
|
import { FilterEventsComponent } from './filter-events.component';
|
||||||
|
import { MatInputModule } from '@angular/material/input';
|
||||||
|
import { MatRadioModule } from '@angular/material/radio';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [FilterEventsComponent],
|
declarations: [FilterEventsComponent],
|
||||||
@ -28,6 +30,8 @@ import { FilterEventsComponent } from './filter-events.component';
|
|||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
ActionKeysModule,
|
ActionKeysModule,
|
||||||
|
MatInputModule,
|
||||||
|
MatRadioModule,
|
||||||
],
|
],
|
||||||
exports: [FilterEventsComponent],
|
exports: [FilterEventsComponent],
|
||||||
})
|
})
|
||||||
|
@ -70,7 +70,7 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="sequence">
|
<ng-container matColumnDef="sequence">
|
||||||
<th mat-header-cell *matHeaderCellDef mat-sort-header [start]="'desc'" [disableClear]="true">
|
<th mat-header-cell *matHeaderCellDef>
|
||||||
{{ 'IAM.EVENTS.SEQUENCE' | translate }}
|
{{ 'IAM.EVENTS.SEQUENCE' | translate }}
|
||||||
</th>
|
</th>
|
||||||
<td mat-cell *matCellDef="let event">
|
<td mat-cell *matCellDef="let event">
|
||||||
@ -81,10 +81,12 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="creationDate">
|
<ng-container matColumnDef="creationDate">
|
||||||
<th mat-header-cell *matHeaderCellDef>{{ 'IAM.EVENTS.CREATIONDATE' | translate }}</th>
|
<th mat-header-cell *matHeaderCellDef mat-sort-header [start]="'desc'" [disableClear]="true">
|
||||||
|
{{ 'IAM.EVENTS.CREATIONDATE' | translate }}
|
||||||
|
</th>
|
||||||
<td mat-cell *matCellDef="let event">
|
<td mat-cell *matCellDef="let event">
|
||||||
<ng-container *ngIf="event | toobject as event">
|
<ng-container *ngIf="event | toobject as event">
|
||||||
<span>{{ event?.creationDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm' }}</span>
|
<span>{{ event?.creationDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm:ss' }}</span>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
@ -176,13 +176,13 @@ export class EventsComponent implements OnDestroy {
|
|||||||
req.setEditorUserId(filterRequest.getEditorUserId());
|
req.setEditorUserId(filterRequest.getEditorUserId());
|
||||||
req.setResourceOwner(filterRequest.getResourceOwner());
|
req.setResourceOwner(filterRequest.getResourceOwner());
|
||||||
req.setSequence(filterRequest.getSequence());
|
req.setSequence(filterRequest.getSequence());
|
||||||
req.setCreationDate(filterRequest.getCreationDate());
|
req.setRange(filterRequest.getRange());
|
||||||
|
req.setFrom(filterRequest.getFrom());
|
||||||
const isAsc: boolean = filterRequest.getAsc();
|
const isAsc: boolean = filterRequest.getAsc();
|
||||||
req.setAsc(isAsc);
|
req.setAsc(isAsc);
|
||||||
if (this.sortAsc !== isAsc) {
|
if (this.sortAsc !== isAsc) {
|
||||||
this.sort.sort({ id: 'sequence', start: isAsc ? 'asc' : 'desc', disableClear: true });
|
this.sort.sort({ id: 'creationDate', start: isAsc ? 'asc' : 'desc', disableClear: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loadEvents(req, true);
|
this.loadEvents(req, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -865,14 +865,16 @@
|
|||||||
},
|
},
|
||||||
"SEQUENCE": {
|
"SEQUENCE": {
|
||||||
"LABEL": "Последователност",
|
"LABEL": "Последователност",
|
||||||
"CHECKBOX": "Филтриране по последователност",
|
"CHECKBOX": "Филтриране по последователност"
|
||||||
|
},
|
||||||
"SORT": "Сортиране",
|
"SORT": "Сортиране",
|
||||||
"ASC": "Възходящ",
|
"ASC": "Възходящ",
|
||||||
"DESC": "Спускане"
|
"DESC": "Спускане",
|
||||||
},
|
|
||||||
"CREATIONDATE": {
|
"CREATIONDATE": {
|
||||||
"LABEL": "Дата на създаване",
|
"RADIO_FROM": "От",
|
||||||
"CHECKBOX": "Филтриране по дата на създаване"
|
"RADIO_RANGE": "Обхват",
|
||||||
|
"LABEL_SINCE": "От",
|
||||||
|
"LABEL_UNTIL": "До"
|
||||||
},
|
},
|
||||||
"OTHER": "друго",
|
"OTHER": "друго",
|
||||||
"OTHERS": "други"
|
"OTHERS": "други"
|
||||||
|
@ -872,14 +872,16 @@
|
|||||||
},
|
},
|
||||||
"SEQUENCE": {
|
"SEQUENCE": {
|
||||||
"LABEL": "Sekvence",
|
"LABEL": "Sekvence",
|
||||||
"CHECKBOX": "Filtrovat podle Sekvence",
|
"CHECKBOX": "Filtrovat podle Sekvence"
|
||||||
|
},
|
||||||
"SORT": "Třídění",
|
"SORT": "Třídění",
|
||||||
"ASC": "Vzestupně",
|
"ASC": "Vzestupně",
|
||||||
"DESC": "Sestupně"
|
"DESC": "Sestupně",
|
||||||
},
|
|
||||||
"CREATIONDATE": {
|
"CREATIONDATE": {
|
||||||
"LABEL": "Datum vytvoření",
|
"RADIO_FROM": "Od",
|
||||||
"CHECKBOX": "Filtrovat podle Datumu vytvoření"
|
"RADIO_RANGE": "Rozsah",
|
||||||
|
"LABEL_SINCE": "Od",
|
||||||
|
"LABEL_UNTIL": "Do"
|
||||||
},
|
},
|
||||||
"OTHER": "jiný",
|
"OTHER": "jiný",
|
||||||
"OTHERS": "jiné"
|
"OTHERS": "jiné"
|
||||||
|
@ -871,14 +871,16 @@
|
|||||||
},
|
},
|
||||||
"SEQUENCE": {
|
"SEQUENCE": {
|
||||||
"LABEL": "Sequenz",
|
"LABEL": "Sequenz",
|
||||||
"CHECKBOX": "Nach Sequenz filtern",
|
"CHECKBOX": "Nach Sequenz filtern"
|
||||||
"SORT": "Sortierung",
|
|
||||||
"ASC": "aufsteigend",
|
|
||||||
"DESC": "absteigend"
|
|
||||||
},
|
},
|
||||||
|
"SORT": "Sortierung",
|
||||||
|
"ASC": "Aufsteigend",
|
||||||
|
"DESC": "Absteigend",
|
||||||
"CREATIONDATE": {
|
"CREATIONDATE": {
|
||||||
"LABEL": "Erstelldatum",
|
"RADIO_FROM": "Von",
|
||||||
"CHECKBOX": "Nach Erstelldatum filtern"
|
"RADIO_RANGE": "Zeitraum",
|
||||||
|
"LABEL_SINCE": "Seit",
|
||||||
|
"LABEL_UNTIL": "Bis"
|
||||||
},
|
},
|
||||||
"OTHER": "weiterer",
|
"OTHER": "weiterer",
|
||||||
"OTHERS": "weitere"
|
"OTHERS": "weitere"
|
||||||
|
@ -872,14 +872,16 @@
|
|||||||
},
|
},
|
||||||
"SEQUENCE": {
|
"SEQUENCE": {
|
||||||
"LABEL": "Sequence",
|
"LABEL": "Sequence",
|
||||||
"CHECKBOX": "Filter by Sequence",
|
"CHECKBOX": "Filter by Sequence"
|
||||||
"SORT": "Sorting",
|
|
||||||
"ASC": "Ascending",
|
|
||||||
"DESC": "Descending"
|
|
||||||
},
|
},
|
||||||
|
"SORT": "Sort",
|
||||||
|
"ASC": "Ascending",
|
||||||
|
"DESC": "Descending",
|
||||||
"CREATIONDATE": {
|
"CREATIONDATE": {
|
||||||
"LABEL": "Creation Date",
|
"RADIO_FROM": "From",
|
||||||
"CHECKBOX": "Filter by Creation Date"
|
"RADIO_RANGE": "Range",
|
||||||
|
"LABEL_SINCE": "Since",
|
||||||
|
"LABEL_UNTIL": "Until"
|
||||||
},
|
},
|
||||||
"OTHER": "other",
|
"OTHER": "other",
|
||||||
"OTHERS": "others"
|
"OTHERS": "others"
|
||||||
|
@ -872,14 +872,16 @@
|
|||||||
},
|
},
|
||||||
"SEQUENCE": {
|
"SEQUENCE": {
|
||||||
"LABEL": "Secuencia",
|
"LABEL": "Secuencia",
|
||||||
"CHECKBOX": "Filtrar por secuencia",
|
"CHECKBOX": "Filtrar por secuencia"
|
||||||
|
},
|
||||||
"SORT": "Ordenado",
|
"SORT": "Ordenado",
|
||||||
"ASC": "Ascendente",
|
"ASC": "Ascendente",
|
||||||
"DESC": "Descendente"
|
"DESC": "Descendente",
|
||||||
},
|
|
||||||
"CREATIONDATE": {
|
"CREATIONDATE": {
|
||||||
"LABEL": "Fecha de creación",
|
"RADIO_FROM": "Desde",
|
||||||
"CHECKBOX": "Filtrar por fecha de creación"
|
"RADIO_RANGE": "Rango",
|
||||||
|
"LABEL_SINCE": "Desde",
|
||||||
|
"LABEL_UNTIL": "Hasta"
|
||||||
},
|
},
|
||||||
"OTHER": "otro",
|
"OTHER": "otro",
|
||||||
"OTHERS": "otros"
|
"OTHERS": "otros"
|
||||||
|
@ -871,14 +871,16 @@
|
|||||||
},
|
},
|
||||||
"SEQUENCE": {
|
"SEQUENCE": {
|
||||||
"LABEL": "séquence",
|
"LABEL": "séquence",
|
||||||
"CHECKBOX": "Filtrer par séquence",
|
"CHECKBOX": "Filtrer par séquence"
|
||||||
|
},
|
||||||
"SORT": "Triage",
|
"SORT": "Triage",
|
||||||
"ASC": "Ascendant",
|
"ASC": "Ascendant",
|
||||||
"DESC": "Descendant"
|
"DESC": "Descendant",
|
||||||
},
|
|
||||||
"CREATIONDATE": {
|
"CREATIONDATE": {
|
||||||
"LABEL": "Date de création",
|
"RADIO_FROM": "De",
|
||||||
"CHECKBOX": "Filtrer par date de création"
|
"RADIO_RANGE": "Gamme",
|
||||||
|
"LABEL_SINCE": "Depuis",
|
||||||
|
"LABEL_UNTIL": "Jusqu'à"
|
||||||
},
|
},
|
||||||
"OTHER": "autre",
|
"OTHER": "autre",
|
||||||
"OTHERS": "autres"
|
"OTHERS": "autres"
|
||||||
|
@ -870,14 +870,16 @@
|
|||||||
},
|
},
|
||||||
"SEQUENCE": {
|
"SEQUENCE": {
|
||||||
"LABEL": "Sequence",
|
"LABEL": "Sequence",
|
||||||
"CHECKBOX": "Filter per sequenza",
|
"CHECKBOX": "Filter per sequenza"
|
||||||
"SORT": "",
|
|
||||||
"ASC": "Ascending",
|
|
||||||
"DESC": "Descending"
|
|
||||||
},
|
},
|
||||||
|
"SORT": "Ordina per",
|
||||||
|
"ASC": "Ascendente",
|
||||||
|
"DESC": "Discendente",
|
||||||
"CREATIONDATE": {
|
"CREATIONDATE": {
|
||||||
"LABEL": "Creation Date",
|
"RADIO_FROM": "Da",
|
||||||
"CHECKBOX": "Filter by Creation Date"
|
"RADIO_RANGE": "Intervallo",
|
||||||
|
"LABEL_SINCE": "Da",
|
||||||
|
"LABEL_UNTIL": "A"
|
||||||
},
|
},
|
||||||
"OTHER": "altro",
|
"OTHER": "altro",
|
||||||
"OTHERS": "altri"
|
"OTHERS": "altri"
|
||||||
|
@ -872,14 +872,16 @@
|
|||||||
},
|
},
|
||||||
"SEQUENCE": {
|
"SEQUENCE": {
|
||||||
"LABEL": "シーケンス",
|
"LABEL": "シーケンス",
|
||||||
"CHECKBOX": "シーケンスで絞り込み",
|
"CHECKBOX": "シーケンスで絞り込み"
|
||||||
|
},
|
||||||
"SORT": "ソート",
|
"SORT": "ソート",
|
||||||
"ASC": "昇順",
|
"ASC": "昇順",
|
||||||
"DESC": "降順"
|
"DESC": "降順",
|
||||||
},
|
|
||||||
"CREATIONDATE": {
|
"CREATIONDATE": {
|
||||||
"LABEL": "作成日",
|
"RADIO_FROM": "から",
|
||||||
"CHECKBOX": "作成日で絞り込み"
|
"RADIO_RANGE": "範囲",
|
||||||
|
"LABEL_SINCE": "以降",
|
||||||
|
"LABEL_UNTIL": "まで"
|
||||||
},
|
},
|
||||||
"OTHER": "その他",
|
"OTHER": "その他",
|
||||||
"OTHERS": "その他"
|
"OTHERS": "その他"
|
||||||
|
@ -872,14 +872,16 @@
|
|||||||
},
|
},
|
||||||
"SEQUENCE": {
|
"SEQUENCE": {
|
||||||
"LABEL": "Секвенца",
|
"LABEL": "Секвенца",
|
||||||
"CHECKBOX": "Филтер според секвенцата",
|
"CHECKBOX": "Филтер според секвенцата"
|
||||||
|
},
|
||||||
"SORT": "Сортирање",
|
"SORT": "Сортирање",
|
||||||
"ASC": "Растечки",
|
"ASC": "Растечки",
|
||||||
"DESC": "Опаѓачки"
|
"DESC": "Опаѓачки",
|
||||||
},
|
|
||||||
"CREATIONDATE": {
|
"CREATIONDATE": {
|
||||||
"LABEL": "Датум на креирање",
|
"RADIO_FROM": "Од",
|
||||||
"CHECKBOX": "Филтер според датумот на креирање"
|
"RADIO_RANGE": "Ранг",
|
||||||
|
"LABEL_SINCE": "Од",
|
||||||
|
"LABEL_UNTIL": "До"
|
||||||
},
|
},
|
||||||
"OTHER": "друго",
|
"OTHER": "друго",
|
||||||
"OTHERS": "други"
|
"OTHERS": "други"
|
||||||
|
@ -872,14 +872,16 @@
|
|||||||
},
|
},
|
||||||
"SEQUENCE": {
|
"SEQUENCE": {
|
||||||
"LABEL": "Reeks",
|
"LABEL": "Reeks",
|
||||||
"CHECKBOX": "Filter op Reeks",
|
"CHECKBOX": "Filter op Reeks"
|
||||||
|
},
|
||||||
"SORT": "Sortering",
|
"SORT": "Sortering",
|
||||||
"ASC": "Oplopend",
|
"ASC": "Oplopend",
|
||||||
"DESC": "Aflopend"
|
"DESC": "Aflopend",
|
||||||
},
|
|
||||||
"CREATIONDATE": {
|
"CREATIONDATE": {
|
||||||
"LABEL": "Aanmaakdatum",
|
"RADIO_FROM": "Van",
|
||||||
"CHECKBOX": "Filter op Aanmaakdatum"
|
"RADIO_RANGE": "Reeks",
|
||||||
|
"LABEL_SINCE": "Sinds",
|
||||||
|
"LABEL_UNTIL": "Tot"
|
||||||
},
|
},
|
||||||
"OTHER": "ander",
|
"OTHER": "ander",
|
||||||
"OTHERS": "anderen"
|
"OTHERS": "anderen"
|
||||||
|
@ -871,14 +871,16 @@
|
|||||||
},
|
},
|
||||||
"SEQUENCE": {
|
"SEQUENCE": {
|
||||||
"LABEL": "Sekwencja",
|
"LABEL": "Sekwencja",
|
||||||
"CHECKBOX": "Filtruj według sekwencji",
|
"CHECKBOX": "Filtruj według sekwencji"
|
||||||
|
},
|
||||||
"SORT": "Sortowanie",
|
"SORT": "Sortowanie",
|
||||||
"ASC": "Rosnące",
|
"ASC": "Rosnące",
|
||||||
"DESC": "Malejące"
|
"DESC": "Malejące",
|
||||||
},
|
|
||||||
"CREATIONDATE": {
|
"CREATIONDATE": {
|
||||||
"LABEL": "Data utworzenia",
|
"RADIO_FROM": "Od",
|
||||||
"CHECKBOX": "Filtruj według daty utworzenia"
|
"RADIO_RANGE": "Zakres",
|
||||||
|
"LABEL_SINCE": "Od",
|
||||||
|
"LABEL_UNTIL": "Do"
|
||||||
},
|
},
|
||||||
"OTHER": "inne",
|
"OTHER": "inne",
|
||||||
"OTHERS": "inni"
|
"OTHERS": "inni"
|
||||||
|
@ -872,14 +872,16 @@
|
|||||||
},
|
},
|
||||||
"SEQUENCE": {
|
"SEQUENCE": {
|
||||||
"LABEL": "Sequência",
|
"LABEL": "Sequência",
|
||||||
"CHECKBOX": "Filtrar por Sequência",
|
"CHECKBOX": "Filtrar por Sequência"
|
||||||
|
},
|
||||||
"SORT": "Ordenação",
|
"SORT": "Ordenação",
|
||||||
"ASC": "Crescente",
|
"ASC": "Crescente",
|
||||||
"DESC": "Decrescente"
|
"DESC": "Decrescente",
|
||||||
},
|
|
||||||
"CREATIONDATE": {
|
"CREATIONDATE": {
|
||||||
"LABEL": "Data de Criação",
|
"RADIO_FROM": "Desde",
|
||||||
"CHECKBOX": "Filtrar por Data de Criação"
|
"RADIO_RANGE": "Intervalo",
|
||||||
|
"LABEL_SINCE": "Desde",
|
||||||
|
"LABEL_UNTIL": "Até"
|
||||||
},
|
},
|
||||||
"OTHER": "outro",
|
"OTHER": "outro",
|
||||||
"OTHERS": "outros"
|
"OTHERS": "outros"
|
||||||
|
@ -868,14 +868,16 @@
|
|||||||
},
|
},
|
||||||
"SEQUENCE": {
|
"SEQUENCE": {
|
||||||
"LABEL": "Последовательность",
|
"LABEL": "Последовательность",
|
||||||
"CHECKBOX": "Фильтровать по последовательности",
|
"CHECKBOX": "Фильтровать по последовательности"
|
||||||
|
},
|
||||||
"SORT": "Сортировка",
|
"SORT": "Сортировка",
|
||||||
"ASC": "Восходящий",
|
"ASC": "Восходящий",
|
||||||
"DESC": "По убыванию"
|
"DESC": "По убыванию",
|
||||||
},
|
|
||||||
"CREATIONDATE": {
|
"CREATIONDATE": {
|
||||||
"LABEL": "Дата создания",
|
"RADIO_FROM": "От",
|
||||||
"CHECKBOX": "Фильтровать по дате создания"
|
"RADIO_RANGE": "Диапазон",
|
||||||
|
"LABEL_SINCE": "С",
|
||||||
|
"LABEL_UNTIL": "К"
|
||||||
},
|
},
|
||||||
"OTHER": "другой",
|
"OTHER": "другой",
|
||||||
"OTHERS": "другие"
|
"OTHERS": "другие"
|
||||||
|
@ -871,14 +871,16 @@
|
|||||||
},
|
},
|
||||||
"SEQUENCE": {
|
"SEQUENCE": {
|
||||||
"LABEL": "序列",
|
"LABEL": "序列",
|
||||||
"CHECKBOX": "按顺序过滤",
|
"CHECKBOX": "按顺序过滤"
|
||||||
|
},
|
||||||
"SORT": "分拣",
|
"SORT": "分拣",
|
||||||
"ASC": "上升中",
|
"ASC": "上升中",
|
||||||
"DESC": "下降"
|
"DESC": "下降",
|
||||||
},
|
|
||||||
"CREATIONDATE": {
|
"CREATIONDATE": {
|
||||||
"LABEL": "创建日期",
|
"RADIO_FROM": "从",
|
||||||
"CHECKBOX": "按创建日期过滤"
|
"RADIO_RANGE": "范围",
|
||||||
|
"LABEL_SINCE": "自从",
|
||||||
|
"LABEL_UNTIL": "直到"
|
||||||
},
|
},
|
||||||
"OTHER": "其他",
|
"OTHER": "其他",
|
||||||
"OTHERS": "其他"
|
"OTHERS": "其他"
|
||||||
|
@ -9,9 +9,8 @@ describe('events', () => {
|
|||||||
cy.get('[data-e2e="event-type-cell"]').should('have.length', 20);
|
cy.get('[data-e2e="event-type-cell"]').should('have.length', 20);
|
||||||
cy.get('[data-e2e="open-filter-button"]').click();
|
cy.get('[data-e2e="open-filter-button"]').click();
|
||||||
cy.get('[data-e2e="event-type-filter-checkbox"]').click();
|
cy.get('[data-e2e="event-type-filter-checkbox"]').click();
|
||||||
cy.get('#mat-select-value-1').click();
|
cy.contains('mat-select', 'Descending').click();
|
||||||
cy.contains('mat-option', eventTypeEnglish).click();
|
cy.contains('mat-option', 'Ascending').click();
|
||||||
cy.get('body').click();
|
|
||||||
cy.get('[data-e2e="filter-finish-button"]').click();
|
cy.get('[data-e2e="filter-finish-button"]').click();
|
||||||
cy.contains('[data-e2e="event-type-cell"]', eventTypeEnglish).should('have.length.at.least', 1);
|
cy.contains('[data-e2e="event-type-cell"]', eventTypeEnglish).should('have.length.at.least', 1);
|
||||||
});
|
});
|
||||||
|
@ -2,6 +2,7 @@ package admin
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/api/authz"
|
"github.com/zitadel/zitadel/internal/api/authz"
|
||||||
"github.com/zitadel/zitadel/internal/eventstore"
|
"github.com/zitadel/zitadel/internal/eventstore"
|
||||||
@ -36,6 +37,25 @@ func (s *Server) ListAggregateTypes(ctx context.Context, in *admin_pb.ListAggreg
|
|||||||
}
|
}
|
||||||
|
|
||||||
func eventRequestToFilter(ctx context.Context, req *admin_pb.ListEventsRequest) (*eventstore.SearchQueryBuilder, error) {
|
func eventRequestToFilter(ctx context.Context, req *admin_pb.ListEventsRequest) (*eventstore.SearchQueryBuilder, error) {
|
||||||
|
var fromTime, sinceTime, untilTime time.Time
|
||||||
|
// We ignore the deprecation warning here because we still need to support the deprecated field.
|
||||||
|
//nolint:staticcheck
|
||||||
|
if creationDatePb := req.GetCreationDate(); creationDatePb != nil {
|
||||||
|
fromTime = creationDatePb.AsTime()
|
||||||
|
}
|
||||||
|
if fromTimePb := req.GetFrom(); fromTimePb != nil {
|
||||||
|
fromTime = fromTimePb.AsTime()
|
||||||
|
}
|
||||||
|
if timeRange := req.GetRange(); timeRange != nil {
|
||||||
|
// If range is set, we ignore the from and the deprecated creation_date fields
|
||||||
|
fromTime = time.Time{}
|
||||||
|
if timeSincePb := timeRange.GetSince(); timeSincePb != nil {
|
||||||
|
sinceTime = timeSincePb.AsTime()
|
||||||
|
}
|
||||||
|
if timeUntilPb := timeRange.GetUntil(); timeUntilPb != nil {
|
||||||
|
untilTime = timeUntilPb.AsTime()
|
||||||
|
}
|
||||||
|
}
|
||||||
eventTypes := make([]eventstore.EventType, len(req.EventTypes))
|
eventTypes := make([]eventstore.EventType, len(req.EventTypes))
|
||||||
for i, eventType := range req.EventTypes {
|
for i, eventType := range req.EventTypes {
|
||||||
eventTypes[i] = eventstore.EventType(eventType)
|
eventTypes[i] = eventstore.EventType(eventType)
|
||||||
@ -60,7 +80,9 @@ func eventRequestToFilter(ctx context.Context, req *admin_pb.ListEventsRequest)
|
|||||||
AwaitOpenTransactions().
|
AwaitOpenTransactions().
|
||||||
ResourceOwner(req.ResourceOwner).
|
ResourceOwner(req.ResourceOwner).
|
||||||
EditorUser(req.EditorUserId).
|
EditorUser(req.EditorUserId).
|
||||||
SequenceGreater(req.Sequence)
|
SequenceGreater(req.Sequence).
|
||||||
|
CreationDateAfter(sinceTime).
|
||||||
|
CreationDateBefore(untilTime)
|
||||||
|
|
||||||
if len(aggregateIDs) > 0 || len(aggregateTypes) > 0 || len(eventTypes) > 0 {
|
if len(aggregateIDs) > 0 || len(aggregateTypes) > 0 || len(eventTypes) > 0 {
|
||||||
builder.AddQuery().
|
builder.AddQuery().
|
||||||
@ -72,10 +94,9 @@ func eventRequestToFilter(ctx context.Context, req *admin_pb.ListEventsRequest)
|
|||||||
|
|
||||||
if req.GetAsc() {
|
if req.GetAsc() {
|
||||||
builder.OrderAsc()
|
builder.OrderAsc()
|
||||||
builder.CreationDateAfter(req.CreationDate.AsTime())
|
builder.CreationDateAfter(fromTime)
|
||||||
} else {
|
} else {
|
||||||
builder.CreationDateBefore(req.CreationDate.AsTime())
|
builder.CreationDateBefore(fromTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder, nil
|
return builder, nil
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ package system_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
@ -23,6 +24,7 @@ func TestServer_Limits_AuditLogRetention(t *testing.T) {
|
|||||||
_, instanceID, iamOwnerCtx := Tester.UseIsolatedInstance(t, CTX, SystemCTX)
|
_, instanceID, iamOwnerCtx := Tester.UseIsolatedInstance(t, CTX, SystemCTX)
|
||||||
userID, projectID, appID, projectGrantID := seedObjects(iamOwnerCtx, t)
|
userID, projectID, appID, projectGrantID := seedObjects(iamOwnerCtx, t)
|
||||||
beforeTime := time.Now()
|
beforeTime := time.Now()
|
||||||
|
farPast := timestamppb.New(beforeTime.Add(-10 * time.Hour).UTC())
|
||||||
zeroCounts := &eventCounts{}
|
zeroCounts := &eventCounts{}
|
||||||
seededCount := requireEventually(t, iamOwnerCtx, userID, projectID, appID, projectGrantID, func(c assert.TestingT, counts *eventCounts) {
|
seededCount := requireEventually(t, iamOwnerCtx, userID, projectID, appID, projectGrantID, func(c assert.TestingT, counts *eventCounts) {
|
||||||
counts.assertAll(t, c, "seeded events are > 0", assert.Greater, zeroCounts)
|
counts.assertAll(t, c, "seeded events are > 0", assert.Greater, zeroCounts)
|
||||||
@ -36,10 +38,22 @@ func TestServer_Limits_AuditLogRetention(t *testing.T) {
|
|||||||
AuditLogRetention: durationpb.New(time.Now().Sub(beforeTime)),
|
AuditLogRetention: durationpb.New(time.Now().Sub(beforeTime)),
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
var limitedCounts *eventCounts
|
||||||
requireEventually(t, iamOwnerCtx, userID, projectID, appID, projectGrantID, func(c assert.TestingT, counts *eventCounts) {
|
requireEventually(t, iamOwnerCtx, userID, projectID, appID, projectGrantID, func(c assert.TestingT, counts *eventCounts) {
|
||||||
counts.assertAll(t, c, "limited events < added events", assert.Less, addedCount)
|
counts.assertAll(t, c, "limited events < added events", assert.Less, addedCount)
|
||||||
counts.assertAll(t, c, "limited events > 0", assert.Greater, zeroCounts)
|
counts.assertAll(t, c, "limited events > 0", assert.Greater, zeroCounts)
|
||||||
|
limitedCounts = counts
|
||||||
}, "wait for limited event assertions to pass")
|
}, "wait for limited event assertions to pass")
|
||||||
|
listedEvents, err := Tester.Client.Admin.ListEvents(iamOwnerCtx, &admin.ListEventsRequest{CreationDateFilter: &admin.ListEventsRequest_From{
|
||||||
|
From: farPast,
|
||||||
|
}})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.LessOrEqual(t, len(listedEvents.GetEvents()), limitedCounts.all, "ListEvents with from query older than retention doesn't return more events")
|
||||||
|
listedEvents, err = Tester.Client.Admin.ListEvents(iamOwnerCtx, &admin.ListEventsRequest{CreationDateFilter: &admin.ListEventsRequest_Range{Range: &admin.ListEventsRequestCreationDateRange{
|
||||||
|
Since: farPast,
|
||||||
|
}}})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.LessOrEqual(t, len(listedEvents.GetEvents()), limitedCounts.all, "ListEvents with since query older than retention doesn't return more events")
|
||||||
_, err = Tester.Client.System.ResetLimits(SystemCTX, &system.ResetLimitsRequest{
|
_, err = Tester.Client.System.ResetLimits(SystemCTX, &system.ResetLimitsRequest{
|
||||||
InstanceId: instanceID,
|
InstanceId: instanceID,
|
||||||
})
|
})
|
||||||
|
@ -7972,11 +7972,35 @@ message ListEventsRequest {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
google.protobuf.Timestamp creation_date = 9 [
|
google.protobuf.Timestamp creation_date = 9 [
|
||||||
|
deprecated = true,
|
||||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
example: "\"2019-04-01T08:45:00.000000Z\"";
|
example: "\"2019-04-01T08:45:00.000000Z\"";
|
||||||
description: "If asc is false, the events returned are older than creation_date. If asc is true, the events returned are younger than creation_date. If creation_date is not set the field is ignored.";
|
description: "Use from instead.";
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
message creation_date_range {
|
||||||
|
google.protobuf.Timestamp since = 1 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
example: "\"2019-04-01T08:45:00.000000Z\"";
|
||||||
|
description: "The events returned are younger than the UTC since date";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
google.protobuf.Timestamp until = 2 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
example: "\"2019-04-01T08:45:00.000000Z\"";
|
||||||
|
description: "The events returned are older than the UTC until date.";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
oneof creation_date_filter {
|
||||||
|
creation_date_range range = 10;
|
||||||
|
google.protobuf.Timestamp from = 11 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
example: "\"2019-04-01T08:45:00.000000Z\"";
|
||||||
|
description: "If asc is false, the events returned are older than the UTC from date. If asc is true, the events returned are younger than from.";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message ListEventsResponse {
|
message ListEventsResponse {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user