diff --git a/frontend/package.json b/frontend/package.json index 9b101de..8019b4b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -24,6 +24,8 @@ "@angular/platform-browser": "^14.0.0-next.15", "@angular/platform-browser-dynamic": "^14.0.0-next.15", "@angular/router": "^14.0.0-next.15", + "@ng-web-apis/common": "^2.0.0", + "@ng-web-apis/resize-observer": "^1.0.3", "@ngui/common": "^1.0.0", "bootstrap": "^5.1.3", "fuse.js": "^6.5.3", @@ -47,6 +49,7 @@ "@fontsource/material-icons-outlined": "^4.5.4", "@fontsource/roboto": "^4.5.5", "@types/node": "^17.0.30", + "@types/resize-observer-browser": "^0.1.7", "@types/validator": "^13.7.2", "typescript": "4.6.4" } diff --git a/frontend/src/app/components/masonry/masonry-item.directive.ts b/frontend/src/app/components/masonry/masonry-item.directive.ts new file mode 100644 index 0000000..8be01f8 --- /dev/null +++ b/frontend/src/app/components/masonry/masonry-item.directive.ts @@ -0,0 +1,54 @@ +import { Directive, ElementRef, Inject } from '@angular/core'; +import { + boxExtractor, + ResizeObserverDirective, + ResizeObserverService, + RESIZE_OPTION_BOX, +} from '@ng-web-apis/resize-observer'; +import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator'; +import { map, Observable } from 'rxjs'; + +@Directive({ + selector: '[masonry-item]', + providers: [ + ResizeObserverService, + { + provide: RESIZE_OPTION_BOX, + deps: [ElementRef], + useFactory: boxExtractor, + }, + ], +}) +export class MasonryItemDirective { + private lastEntry: ResizeObserverEntry | null = null; + + private resizeObserver: Observable; + + constructor( + private element: ElementRef, + @Inject(ResizeObserverService) + resize: Observable + ) { + this.resizeObserver = resize.pipe(map((entries) => entries[0])); + this.subscribeResize(); + } + + @AutoUnsubscribe() + private subscribeResize() { + return this.resizeObserver.subscribe((value) => { + this.lastEntry = value; + }); + } + + public getElement() { + return this.element.nativeElement; + } + + public getSize() { + return this.resizeObserver; + } + + public getLastSize() { + return this.lastEntry; + } +} diff --git a/frontend/src/app/components/masonry/masonry.component.html b/frontend/src/app/components/masonry/masonry.component.html new file mode 100644 index 0000000..6dbc743 --- /dev/null +++ b/frontend/src/app/components/masonry/masonry.component.html @@ -0,0 +1 @@ + diff --git a/frontend/src/app/components/masonry/masonry.component.scss b/frontend/src/app/components/masonry/masonry.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/app/components/masonry/masonry.component.ts b/frontend/src/app/components/masonry/masonry.component.ts new file mode 100644 index 0000000..97d3e90 --- /dev/null +++ b/frontend/src/app/components/masonry/masonry.component.ts @@ -0,0 +1,34 @@ +import { + AfterViewInit, + Component, + ContentChildren, + ElementRef, + OnChanges, + OnInit, + QueryList, + SimpleChanges, + ViewChild, +} from '@angular/core'; +import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator'; +import { MasonryItemDirective } from './masonry-item.directive'; + +@Component({ + selector: 'masonry', + templateUrl: './masonry.component.html', + styleUrls: ['./masonry.component.scss'], +}) +export class MasonryComponent implements AfterViewInit { + @ContentChildren(MasonryItemDirective) + content: QueryList; + + ngAfterViewInit(): void { + this.subscribeContent(); + } + + @AutoUnsubscribe() + private subscribeContent() { + return this.content.changes.subscribe((items) => { + console.log('a', items.toArray()); + }); + } +} diff --git a/frontend/src/app/components/masonry/masonry.module.ts b/frontend/src/app/components/masonry/masonry.module.ts new file mode 100644 index 0000000..725be4f --- /dev/null +++ b/frontend/src/app/components/masonry/masonry.module.ts @@ -0,0 +1,11 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { MasonryComponent } from './masonry.component'; +import { MasonryItemDirective } from './masonry-item.directive'; + +@NgModule({ + declarations: [MasonryComponent, MasonryItemDirective], + imports: [CommonModule], + exports: [MasonryComponent, MasonryItemDirective], +}) +export class MasonryModule {} diff --git a/frontend/src/app/components/picsur-img/picsur-img.component.ts b/frontend/src/app/components/picsur-img/picsur-img.component.ts index 4e55c27..22fca12 100644 --- a/frontend/src/app/components/picsur-img/picsur-img.component.ts +++ b/frontend/src/app/components/picsur-img/picsur-img.component.ts @@ -1,4 +1,6 @@ import { + ChangeDetectionStrategy, + ChangeDetectorRef, Component, ElementRef, Input, @@ -25,6 +27,7 @@ enum PicsurImgState { selector: 'picsur-img', templateUrl: './picsur-img.component.html', styleUrls: ['./picsur-img.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush }) export class PicsurImgComponent implements OnChanges { private readonly logger = new Logger('ZodImgComponent'); @@ -39,7 +42,8 @@ export class PicsurImgComponent implements OnChanges { constructor( private qoiWorker: QoiWorkerService, - private apiService: ApiService + private apiService: ApiService, + private changeDetector: ChangeDetectorRef ) {} ngOnChanges(changes: SimpleChanges): void { @@ -50,6 +54,7 @@ export class PicsurImgComponent implements OnChanges { let url = this.imageURL ?? ''; if (!URLRegex.test(url)) { this.state = PicsurImgState.Loading; + this.changeDetector.markForCheck(); return; } @@ -61,6 +66,8 @@ export class PicsurImgComponent implements OnChanges { } }) .catch((e) => this.logger.error); + + } private async update(url: string): AsyncFailable { @@ -80,6 +87,7 @@ export class PicsurImgComponent implements OnChanges { } else { this.state = PicsurImgState.Image; } + this.changeDetector.markForCheck(); } private async getMime(url: string): AsyncFailable { diff --git a/frontend/src/app/routes/images/images.component.html b/frontend/src/app/routes/images/images.component.html index 949ad52..2daa283 100644 --- a/frontend/src/app/routes/images/images.component.html +++ b/frontend/src/app/routes/images/images.component.html @@ -1,9 +1,33 @@ + +
+ + + Image by you + + Uploaded {{ image.created | amTimeAgo }} + + + + + + + + + +
+
+
-
+
Image by you @@ -25,3 +49,30 @@
+ + diff --git a/frontend/src/app/routes/images/images.component.scss b/frontend/src/app/routes/images/images.component.scss index 5811460..19bf1dd 100644 --- a/frontend/src/app/routes/images/images.component.scss +++ b/frontend/src/app/routes/images/images.component.scss @@ -9,3 +9,13 @@ flex-basis: 0; flex-direction: column; } + +.paginator { + display: flex; + flex-direction: row; + justify-content: center; + + button { + margin-inline: .5em; + } +} \ No newline at end of file diff --git a/frontend/src/app/routes/images/images.component.ts b/frontend/src/app/routes/images/images.component.ts index bdc26b0..6e9bb88 100644 --- a/frontend/src/app/routes/images/images.component.ts +++ b/frontend/src/app/routes/images/images.component.ts @@ -1,4 +1,11 @@ -import { Component, OnInit } from '@angular/core'; +import { + Component, + ElementRef, + OnInit, + QueryList, + ViewChildren, + ViewRef, +} from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator'; import { SupportedMime } from 'picsur-shared/dist/dto/mimes.dto'; @@ -19,8 +26,15 @@ import { UtilService } from 'src/app/util/util-module/util.service'; export class ImagesComponent implements OnInit { private readonly logger: Logger = new Logger('ImagesComponent'); - images: EImage[] | null = null; - columns = 3; + @ViewChildren('column') + columnsChild: QueryList>; + + sourceImages: EImage[] | null = null; + private elementSizes: { [key: string]: number } = {}; + private elements: { [key: string]: HTMLElement } = {}; + private desiredColumns = 1; + + images: EImage[][] | null = null; constructor( private readonly route: ActivatedRoute, @@ -42,22 +56,90 @@ export class ImagesComponent implements OnInit { return this.logger.error(result.getReason()); } - this.images = result.images; + this.sourceImages = result.images; + this.sortMasonryRender(); } @AutoUnsubscribe() private subscribeMobile() { return this.bootstrapService.screenSize().subscribe((size) => { if (size <= BSScreenSize.sm) { - this.columns = 1; + this.desiredColumns = 1; } else if (size <= BSScreenSize.lg) { - this.columns = 2; + this.desiredColumns = 2; } else { - this.columns = 3; + this.desiredColumns = 3; } + this.sortMasonryRender(); }); } + private sortMasonryRender() { + if (!this.sourceImages) { + this.images = null; + return; + } + + this.elements = {}; + this.elementSizes = {}; + + const columnSizes: number[] = []; + const columns: EImage[][] = []; + for (let i = 0; i < this.desiredColumns; i++) { + columnSizes.push(0); + columns.push([]); + } + + for (let i = 0; i < this.sourceImages.length; i++) { + columns[i % this.desiredColumns].push(this.sourceImages[i]); + } + + this.images = columns; + } + + private sortMasonry() { + if (!this.sourceImages) { + this.images = null; + return; + } + + const elementImages = this.sourceImages.map((img) => ({ + element: this.elements[img.id], + height: this.elementSizes[img.id], + })); + if ( + elementImages.find( + (test) => test.element === undefined || test.height === undefined + ) !== undefined + ) { + return; + } + + for (let { element } of elementImages) { + element.parentElement?.removeChild(element); + } + + const columnSizes: number[] = this.columnsChild.map((column) => 0); + for (let i = 0; i < elementImages.length; i++) { + const { element, height } = elementImages[i]; + + let minColumn = 0; + let minColumnSize = columnSizes[0]; + for (let j = 0; j < columnSizes.length; j++) { + const distributed_j = (j + i) % columnSizes.length; + + const columnSize = columnSizes[distributed_j]; + if (columnSize <= minColumnSize) { + minColumn = distributed_j; + minColumnSize = columnSize; + } + } + + this.columnsChild.toArray()[minColumn].nativeElement.appendChild(element); + columnSizes[minColumn] += height; + } + } + getThumbnailUrl(image: EImage) { return ( this.imageService.GetImageURL(image.id, SupportedMime.QOI) + '?height=480' @@ -67,4 +149,17 @@ export class ImagesComponent implements OnInit { viewImage(image: EImage) { this.router.navigate(['/view', image.id]); } + + onResize( + [event]: ResizeObserverEntry[], + image: EImage, + element: HTMLElement + ) { + this.elements[image.id] = element; + + if (this.elementSizes[image.id] !== event.contentRect.height) { + this.elementSizes[image.id] = event.contentRect.height; + this.sortMasonry(); + } + } } diff --git a/frontend/src/app/routes/images/images.module.ts b/frontend/src/app/routes/images/images.module.ts index df7bb5e..86330de 100644 --- a/frontend/src/app/routes/images/images.module.ts +++ b/frontend/src/app/routes/images/images.module.ts @@ -7,6 +7,10 @@ import { ImagesComponent } from './images.component'; import { ImagesRoutingModule } from './images.routing.module'; import { MasonryPipe } from './masonry.pipe'; import { MomentModule } from 'ngx-moment'; +import { MatPaginatorModule } from '@angular/material/paginator'; +import { MatIconModule } from '@angular/material/icon'; +import { ResizeObserverModule } from '@ng-web-apis/resize-observer'; +import { MasonryModule } from 'src/app/components/masonry/masonry.module'; @NgModule({ declarations: [ImagesComponent, MasonryPipe], @@ -15,6 +19,10 @@ import { MomentModule } from 'ngx-moment'; ImagesRoutingModule, MatCardModule, MatButtonModule, + MatPaginatorModule, + MatIconModule, + ResizeObserverModule, + MasonryModule, PicsurImgModule, MomentModule, ], diff --git a/frontend/src/app/routes/settings/roles/settings-roles.component.html b/frontend/src/app/routes/settings/roles/settings-roles.component.html index fb4e583..7de22ce 100644 --- a/frontend/src/app/routes/settings/roles/settings-roles.component.html +++ b/frontend/src/app/routes/settings/roles/settings-roles.component.html @@ -74,7 +74,7 @@ class="mat-elevation-z2" [pageSizeOptions]="pageSizeOptions" [pageSize]="startingPageSize" - [showFirstLastButtons]="bootstrapService.isDesktop() | async" + [showFirstLastButtons]="bootstrapService.isNotMobile() | async" [hidePageSize]="bootstrapService.isMobile() | async" aria-label="Select page of roles" > diff --git a/frontend/src/app/services/api/api.service.ts b/frontend/src/app/services/api/api.service.ts index 6aef7d3..78c0f3f 100644 --- a/frontend/src/app/services/api/api.service.ts +++ b/frontend/src/app/services/api/api.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@angular/core'; +import { Inject, Injectable } from '@angular/core'; import { ApiResponseSchema } from 'picsur-shared/dist/dto/api/api.dto'; import { Mime2Ext } from 'picsur-shared/dist/dto/mimes.dto'; import { AsyncFailable, Fail, HasFailed } from 'picsur-shared/dist/types'; @@ -10,6 +10,7 @@ import { z } from 'zod'; import { MultiPartRequest } from '../../models/dto/multi-part-request.dto'; import { Logger } from '../logger/logger.service'; import { KeyService } from '../storage/key.service'; +import { WINDOW } from '@ng-web-apis/common'; /* Proud of this, it works so smoooth @@ -27,7 +28,10 @@ export class ApiService { return this.errorSubject.asObservable(); } - constructor(private keyService: KeyService) {} + constructor( + private readonly keyService: KeyService, + @Inject(WINDOW) readonly windowRef: Window + ) {} public async get( type: ZodDtoStatic, @@ -176,7 +180,7 @@ export class ApiService { if (isJSON) headers['Content-Type'] = 'application/json'; options.headers = headers; - return await window.fetch(url, options); + return await this.windowRef.fetch(url, options); } catch (e) { this.errorSubject.next({ error: e, diff --git a/frontend/src/app/services/api/image.service.ts b/frontend/src/app/services/api/image.service.ts index c17452b..934ac0c 100644 --- a/frontend/src/app/services/api/image.service.ts +++ b/frontend/src/app/services/api/image.service.ts @@ -1,10 +1,11 @@ -import { Injectable } from '@angular/core'; +import { Inject, Injectable } from '@angular/core'; +import { LOCATION, WINDOW } from '@ng-web-apis/common'; import { ImageDeleteRequest, ImageDeleteResponse, ImageListRequest, ImageListResponse, - ImageUploadResponse + ImageUploadResponse, } from 'picsur-shared/dist/dto/api/image-manage.dto'; import { ImageMetaResponse } from 'picsur-shared/dist/dto/api/image.dto'; import { ImageLinks } from 'picsur-shared/dist/dto/image-links.dto'; @@ -19,7 +20,10 @@ import { ApiService } from './api.service'; providedIn: 'root', }) export class ImageService { - constructor(private api: ApiService) {} + constructor( + private api: ApiService, + @Inject(LOCATION) readonly location: Location, + ) {} public async UploadImage(image: File): AsyncFailable { const result = await this.api.postForm( @@ -81,7 +85,7 @@ export class ImageService { // Non api calls public GetImageURL(image: string, mime: string | null): string { - const baseURL = window.location.protocol + '//' + window.location.host; + const baseURL = this.location.protocol + '//' + this.location.host; const extension = mime !== null ? Mime2Ext(mime) ?? 'error' : null; return `${baseURL}/i/${image}${extension !== null ? '.' + extension : ''}`; diff --git a/frontend/src/app/services/api/info.service.ts b/frontend/src/app/services/api/info.service.ts index f40057a..87dd32b 100644 --- a/frontend/src/app/services/api/info.service.ts +++ b/frontend/src/app/services/api/info.service.ts @@ -1,9 +1,7 @@ -import { Injectable } from '@angular/core'; +import { Inject, Injectable } from '@angular/core'; +import { HISTORY } from '@ng-web-apis/common'; import { InfoResponse } from 'picsur-shared/dist/dto/api/info.dto'; -import { - AsyncFailable, - Fail, HasFailed -} from 'picsur-shared/dist/types'; +import { AsyncFailable, Fail, HasFailed } from 'picsur-shared/dist/types'; import { SemVerRegex } from 'picsur-shared/dist/util/common-regex'; import { BehaviorSubject } from 'rxjs'; import { SnackBarType } from 'src/app/models/dto/snack-bar-type.dto'; @@ -25,7 +23,11 @@ export class InfoService { private infoSubject = new BehaviorSubject(new ServerInfo()); - constructor(private api: ApiService, private utilService: UtilService) { + constructor( + private readonly api: ApiService, + private readonly utilService: UtilService, + @Inject(HISTORY) private readonly history: History + ) { this.checkCompatibility().catch(this.logger.error); } @@ -104,7 +106,7 @@ export class InfoService { } else { this.checkCompatibility(); // Go to previous page - window.history.back(); + this.history.back(); } }); } diff --git a/frontend/src/app/services/storage/cache.service.ts b/frontend/src/app/services/storage/cache.service.ts index 8a289a1..38e9c9e 100644 --- a/frontend/src/app/services/storage/cache.service.ts +++ b/frontend/src/app/services/storage/cache.service.ts @@ -1,4 +1,5 @@ -import { Injectable } from '@angular/core'; +import { Inject, Injectable } from '@angular/core'; +import { SESSION_STORAGE } from '@ng-web-apis/common'; import { AsyncFailable, Failable, HasFailed } from 'picsur-shared/dist/types'; interface dataWrapper { @@ -12,15 +13,7 @@ interface dataWrapper { export class CacheService { private readonly cacheExpiresMS = 1000 * 60 * 60; - private storage: Storage; - - constructor() { - if (window.sessionStorage) { - this.storage = window.sessionStorage; - } else { - throw new Error('Session storage is not supported'); - } - } + constructor(@Inject(SESSION_STORAGE) private readonly storage: Storage) {} public set(key: string, value: T): void { const data: dataWrapper = { diff --git a/frontend/src/scss/fixes.scss b/frontend/src/scss/fixes.scss index 3f16b98..d4f8fc2 100644 --- a/frontend/src/scss/fixes.scss +++ b/frontend/src/scss/fixes.scss @@ -48,6 +48,10 @@ router-outlet ~ * { width: initial !important; } +button.mat-icon-button { + line-height: unset; +} + .row { width: 100%; } diff --git a/picsur.code-workspace b/picsur.code-workspace index 59dcdb3..6821fd3 100644 --- a/picsur.code-workspace +++ b/picsur.code-workspace @@ -72,6 +72,7 @@ }, "settings": { "vsicons.presets.angular": true, - "skipRefreshExplorerOnWindowFocus": true + "skipRefreshExplorerOnWindowFocus": true, + "angular.log": "verbose" } } diff --git a/yarn.lock b/yarn.lock index 2ea0d66..655e34d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1373,7 +1373,8 @@ secure-json-parse "^2.4.0" stream-wormhole "^1.1.0" -"@fastify/static@^5.0.0", fastify-static@^4.7.0, "fastify-static@npm:@fastify/static": +"@fastify/static@^5.0.0", "fastify-static@npm:@fastify/static": + name fastify-static version "5.0.2" resolved "https://registry.yarnpkg.com/@fastify/static/-/static-5.0.2.tgz#46cee887393b422f4b10a46a14e970a64dd086d4" integrity sha512-HvyXZ5a7hUHoSBRq9jKUuKIUCkHMkCDcmiAeEmixXlGOx8pEWx3NYOIaiivcjWa6/NLvfdUT+t/jzfVQ2PA7Gw== @@ -1607,6 +1608,20 @@ dependencies: uuid "8.3.2" +"@ng-web-apis/common@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@ng-web-apis/common/-/common-2.0.0.tgz#6a90f2eb575a595e6fee36f7f57ec38ca901aa17" + integrity sha512-2Vnp4WTEqKZArhbKLgD1JIKjsDa3hWCa67OWaRWRH5sgX5xneVVaIAvC8gVpiCfl2p1Roen2kxfyYngx7G64SQ== + dependencies: + tslib "^2.2.0" + +"@ng-web-apis/resize-observer@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@ng-web-apis/resize-observer/-/resize-observer-1.0.3.tgz#7f594f588d6706bfdeab514dec6249b5afc44534" + integrity sha512-ddmhxlca4knmN7BicgPTBScYXNTEKKF3z2WXPgmhOTxhVOyg/HHRDtq5nDljJt1eEaut2gcnhgDm4/6eGfedWw== + dependencies: + tslib "^1.9.0" + "@ngtools/webpack@14.0.0-next.12": version "14.0.0-next.12" resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-14.0.0-next.12.tgz#6920a8a54abd2a5bc41f671ed4e18d8b3be0502b" @@ -1942,6 +1957,11 @@ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== +"@types/resize-observer-browser@^0.1.7": + version "0.1.7" + resolved "https://registry.yarnpkg.com/@types/resize-observer-browser/-/resize-observer-browser-0.1.7.tgz#294aaadf24ac6580b8fbd1fe3ab7b59fe85f9ef3" + integrity sha512-G9eN0Sn0ii9PWQ3Vl72jDPgeJwRWhv2Qk/nQkJuWmRmOB4HX3/BhD5SE1dZs/hzPZL/WKnvF0RHdTSG54QJFyg== + "@types/retry@0.12.0": version "0.12.0" resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" @@ -4006,6 +4026,27 @@ fastify-plugin@^3.0.0: resolved "https://registry.yarnpkg.com/fastify-plugin/-/fastify-plugin-3.0.1.tgz#79e84c29f401020f38b524f59f2402103fd21ed2" integrity sha512-qKcDXmuZadJqdTm6vlCqioEbyewF60b/0LOFCcYN1B6BIZGlYJumWWOYs70SFYLDAH4YqdE1cxH/RKMG7rFxgA== +"fastify-static-deprecated@npm:fastify-static@4.6.1": + version "4.6.1" + resolved "https://registry.yarnpkg.com/fastify-static/-/fastify-static-4.6.1.tgz#687131da76f1d4391fb8b47f71ea2118cdc85803" + integrity sha512-vy7N28U4AMhuOim12ZZWHulEE6OQKtzZbHgiB8Zj4llUuUQXPka0WHAQI3njm1jTCx4W6fixUHfpITxweMtAIA== + dependencies: + content-disposition "^0.5.3" + encoding-negotiator "^2.0.1" + fastify-plugin "^3.0.0" + glob "^7.1.4" + p-limit "^3.1.0" + readable-stream "^3.4.0" + send "^0.17.1" + +fastify-static@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/fastify-static/-/fastify-static-4.7.0.tgz#e802658d69c1dcddb380b9afc2456d467a3494be" + integrity sha512-zZhCfJv/hkmud2qhWqpU3K9XVAuy3+IV8Tp9BC5J5U+GyA2XwoB6h8lh9GqpEIqdXOw01WyWQllV7dOWVyAlXg== + dependencies: + fastify-static-deprecated "npm:fastify-static@4.6.1" + process-warning "^1.0.0" + fastify@3.28.0: version "3.28.0" resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.28.0.tgz#14d939a2f176b82af1094de7abcb0b2d83bcff8f" @@ -5404,7 +5445,12 @@ minimatch@^3.0.4, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" -minimist@1.2.6, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6, "minimist@npm:minimist-lite": +minimist@1.2.6, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== + +"minimist@npm:minimist-lite": version "2.2.1" resolved "https://registry.yarnpkg.com/minimist-lite/-/minimist-lite-2.2.1.tgz#abb71db2c9b454d7cf4496868c03e9802de9934d" integrity sha512-RSrWIRWGYoM2TDe102s7aIyeSipXMIXKb1fSHYx1tAbxAV0z4g2xR6ra3oPzkTqFb0EIUz1H3A/qvYYeDd+/qQ== @@ -7866,7 +7912,7 @@ tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.0, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.4.0: +tslib@^2.0.0, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==