From bc0f83c3214e7ad91011895f288cc3cb9acade92 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Tue, 14 Nov 2023 11:10:08 +0100 Subject: [PATCH 01/44] feat: notifications core service draft --- .../postgresRunners/PostgresDockerRunner.kt | 2 +- .../postgresRunners/PostgresEmbeddedRunner.kt | 2 +- .../kotlin/io/tolgee/model/Notification.kt | 78 ++++++++++++ .../notifications/NotificationPushEvent.kt | 21 ++++ .../notifications/NotificationService.kt | 115 ++++++++++++++++++ .../listeners/ActivityEventListener.kt | 50 ++++++++ .../listeners/BatchJobListener.kt | 51 ++++++++ .../repository/NotificationsRepository.kt | 64 ++++++++++ 8 files changed, 381 insertions(+), 2 deletions(-) create mode 100644 backend/data/src/main/kotlin/io/tolgee/model/Notification.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPushEvent.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/NotificationService.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/repository/NotificationsRepository.kt diff --git a/backend/app/src/main/kotlin/io/tolgee/postgresRunners/PostgresDockerRunner.kt b/backend/app/src/main/kotlin/io/tolgee/postgresRunners/PostgresDockerRunner.kt index be842e981e..9dbeb92cc1 100644 --- a/backend/app/src/main/kotlin/io/tolgee/postgresRunners/PostgresDockerRunner.kt +++ b/backend/app/src/main/kotlin/io/tolgee/postgresRunners/PostgresDockerRunner.kt @@ -41,7 +41,7 @@ class PostgresDockerRunner( } override val datasourceUrl by lazy { - "jdbc:postgresql://localhost:${postgresAutostartProperties.port}/${postgresAutostartProperties.databaseName}" + "jdbc:postgresql://localhost:${postgresAutostartProperties.port}/${postgresAutostartProperties.databaseName}?reWriteBatchedInserts=true" } @PreDestroy diff --git a/backend/app/src/main/kotlin/io/tolgee/postgresRunners/PostgresEmbeddedRunner.kt b/backend/app/src/main/kotlin/io/tolgee/postgresRunners/PostgresEmbeddedRunner.kt index dccc52c8f4..003022a7b1 100644 --- a/backend/app/src/main/kotlin/io/tolgee/postgresRunners/PostgresEmbeddedRunner.kt +++ b/backend/app/src/main/kotlin/io/tolgee/postgresRunners/PostgresEmbeddedRunner.kt @@ -82,7 +82,7 @@ class PostgresEmbeddedRunner( override val datasourceUrl by lazy { // It's not that easy to change port in embedded version, since there is no env prop for that - "jdbc:postgresql://localhost:$POSTGRES_PORT/${postgresAutostartProperties.databaseName}" + "jdbc:postgresql://localhost:$POSTGRES_PORT/${postgresAutostartProperties.databaseName}?reWriteBatchedInserts=true" } private fun isPostgresUp(): Boolean { diff --git a/backend/data/src/main/kotlin/io/tolgee/model/Notification.kt b/backend/data/src/main/kotlin/io/tolgee/model/Notification.kt new file mode 100644 index 0000000000..5e47be121b --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/model/Notification.kt @@ -0,0 +1,78 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.model + +import io.tolgee.model.activity.ActivityRevision +import io.tolgee.model.batch.BatchJob +import org.hibernate.annotations.Check +import org.hibernate.annotations.CreationTimestamp +import org.hibernate.annotations.UpdateTimestamp +import java.util.* +import javax.persistence.* + +@Entity +class Notification private constructor( + @Column(nullable = false) + @Enumerated(EnumType.STRING) + val type: NotificationType, + + @ManyToOne(fetch = FetchType.EAGER, cascade = [ CascadeType.ALL ]) // We most definitely need this to show the notification: eager + @JoinColumn(nullable = false) + val project: Project, + + @Check(constraints = "activity_revision IS NULL OR type == \"ACTIVITY\"") + @ManyToMany(fetch = FetchType.EAGER, cascade = [ CascadeType.ALL ]) // We most definitely need this to show the notification: eager + @JoinTable(name = "notification_activity_revisions") + val activityRevisions: MutableList? = null, + + @Check(constraints = "batch_job IS NULL OR type == \"BATCH_JOB_FAILURE\"") + @ManyToOne(fetch = FetchType.EAGER, cascade = [ CascadeType.ALL ]) // We most definitely need this to show the notification: eager + @Column(name = "batch_job") + val batchJob: BatchJob? = null, +) { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + val id: Long = 0 + + @Column(nullable = false) + var unread: Boolean = false + + // It is a `lateinit` since during notification creation, the user is provided externally. + // However, because it's non-nullable in DB it'll never actually be `null` besides during creation. + // It allows not polluting the entire code with a nullable type. + @ManyToOne(fetch = FetchType.LAZY, cascade = [ CascadeType.ALL ]) // This data is very likely to be useless: lazy + @JoinColumn(nullable = false) + lateinit var recipient: UserAccount + + var markedDoneAt: Date? = null + + @CreationTimestamp + @UpdateTimestamp + @OrderBy + val lastUpdated: Date = Date() + + constructor(project: Project, activityRevision: ActivityRevision) : + this(NotificationType.ACTIVITY, project, activityRevisions = mutableListOf(activityRevision)) + + constructor(project: Project, batchJob: BatchJob) : + this(NotificationType.BATCH_JOB_FAILURE, project, batchJob = batchJob) + + enum class NotificationType { + ACTIVITY, + BATCH_JOB_FAILURE, + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPushEvent.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPushEvent.kt new file mode 100644 index 0000000000..f2592b453e --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPushEvent.kt @@ -0,0 +1,21 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.notifications + +import io.tolgee.model.Notification + +data class NotificationPushEvent(val notifications: Set) diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationService.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationService.kt new file mode 100644 index 0000000000..967c4a5b0a --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationService.kt @@ -0,0 +1,115 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.notifications + +import io.tolgee.model.Notification +import io.tolgee.model.UserAccount +import io.tolgee.repository.NotificationsRepository +import org.springframework.context.ApplicationEventPublisher +import org.springframework.data.domain.Pageable +import org.springframework.scheduling.annotation.Async +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.util.EnumSet + +@Service +class NotificationService( + private val notificationsRepository: NotificationsRepository, + private val applicationEventPublisher: ApplicationEventPublisher, +) { + @Async + @Transactional + fun dispatchNotification(notification: Notification, user: UserAccount) = + dispatchNotification(notification, setOf(user)) + + @Async + @Transactional + fun dispatchNotification(notification: Notification, users: Set) { + val localUsers = users.toMutableSet() + val notificationObjects = mutableSetOf() + + if (debouncedNotificationTypes.contains(notification.type)) { + val existingNotifications = notificationsRepository.findAllByUnreadTrueAndTypeAndProjectAndRecipientIn( + notification.type, + notification.project, + users, + ) + + existingNotifications.forEach { + localUsers.remove(it.recipient) + + when (notification.type) { + Notification.NotificationType.ACTIVITY -> + it.activityRevisions!!.addAll(notification.activityRevisions!!) + else -> + throw RuntimeException("Cannot debounce notification type ${notification.type}") + } + } + + // Push modifications + notificationObjects.addAll( + notificationsRepository.saveAll(existingNotifications) + ) + } + + // Create notifications + localUsers.forEach { + notification.recipient = it + notificationObjects.add( + notificationsRepository.save(notification) + ) + } + + // Dispatch event + applicationEventPublisher.publishEvent( + NotificationPushEvent(notificationObjects) + ) + } + + fun getNotificationsNotDone(user: UserAccount, pageable: Pageable): Collection { + return notificationsRepository.findAllByMarkedDoneAtNullAndRecipient(user, pageable) + } + + fun getNotificationsDone(user: UserAccount, pageable: Pageable): Collection { + return notificationsRepository.findAllByMarkedDoneAtNotNullAndRecipient(user, pageable) + } + + fun getUnreadNotificationsCount(user: UserAccount): Int { + return notificationsRepository.countNotificationsByRecipientAndUnreadTrue(user) + } + + fun markAsRead(user: UserAccount, notifications: Set) { + return notificationsRepository.markAllAsRead(user) + } + + fun markAllAsRead(user: UserAccount) { + return notificationsRepository.markAllAsRead(user) + } + + fun markAsDone(user: UserAccount, notifications: Set) { + return notificationsRepository.markAllAsDone(user) + } + + fun markAllAsDone(user: UserAccount) { + return notificationsRepository.markAllAsDone(user) + } + + companion object { + val debouncedNotificationTypes: EnumSet + = EnumSet.of(Notification.NotificationType.ACTIVITY) + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt new file mode 100644 index 0000000000..be39437a19 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt @@ -0,0 +1,50 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.notifications.listeners + +import io.tolgee.events.OnProjectActivityStoredEvent +import io.tolgee.model.Notification +import io.tolgee.model.UserAccount +import io.tolgee.model.activity.ActivityRevision +import io.tolgee.notifications.NotificationService +import io.tolgee.service.project.ProjectService +import org.springframework.context.event.EventListener +import org.springframework.stereotype.Component + +@Component +class ActivityEventListener( + private val projectService: ProjectService, + private val notificationService: NotificationService, +) { + @EventListener + fun onActivityRevision(e: OnProjectActivityStoredEvent) { + val id = e.activityRevision.projectId ?: return + + val users = getUsersConcernedByRevision(e.activityRevision) + val notification = Notification( + projectService.get(id), + e.activityRevision, + ) + + notificationService.dispatchNotification(notification, users) + } + + private fun getUsersConcernedByRevision(revision: ActivityRevision): Set { + // TODO!! + return emptySet() + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt new file mode 100644 index 0000000000..e16dd11ac5 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt @@ -0,0 +1,51 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.notifications.listeners + +import io.tolgee.batch.BatchJobService +import io.tolgee.batch.events.OnBatchJobFailed +import io.tolgee.model.Notification +import io.tolgee.notifications.NotificationService +import io.tolgee.service.project.ProjectService +import io.tolgee.service.security.UserAccountService +import org.springframework.context.event.EventListener +import org.springframework.stereotype.Component + +@Component +class BatchJobListener( + private val userAccountService: UserAccountService, + private val projectService: ProjectService, + private val batchJobService: BatchJobService, + private val notificationService: NotificationService, +) { + @EventListener + fun onBatchJobError(e: OnBatchJobFailed) { + val userId = e.job.authorId ?: return + val projectId = e.job.projectId + + val user = userAccountService.get(userId) + val project = projectService.get(projectId) + val job = batchJobService.getJobEntity(e.job.id) + + val notification = Notification( + project, + job, + ) + + notificationService.dispatchNotification(notification, user) + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/NotificationsRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/NotificationsRepository.kt new file mode 100644 index 0000000000..b28cda809d --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/repository/NotificationsRepository.kt @@ -0,0 +1,64 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.repository + +import io.tolgee.model.Notification +import io.tolgee.model.Project +import io.tolgee.model.UserAccount +import org.springframework.data.domain.Pageable +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.stereotype.Repository + +@Repository +interface NotificationsRepository : JpaRepository { + fun findAllByMarkedDoneAtNullAndRecipient(recipient: UserAccount, pageable: Pageable): Collection + + fun findAllByMarkedDoneAtNotNullAndRecipient(recipient: UserAccount, pageable: Pageable): Collection + + fun findAllByUnreadTrueAndTypeAndProjectAndRecipientIn( + type: Notification.NotificationType, + project: Project, + recipients: Collection, + ): Collection + + fun countNotificationsByRecipientAndUnreadTrue(recipient: UserAccount): Int + + @Query("UPDATE Notification n SET n.unread = false WHERE n.recipient = ?1 AND n.id IN ?2") + fun markAsRead(recipient: UserAccount, notifications: Collection) + + @Query("UPDATE Notification n SET n.unread = false WHERE n.recipient = ?1") + fun markAllAsRead(recipient: UserAccount) + + @Query("UPDATE Notification n SET n.unread = true WHERE n.recipient = ?1 AND n.id IN ?2") + fun markAsUnread(recipient: UserAccount, notifications: Collection) + + @Query("UPDATE Notification n SET n.unread = true WHERE n.recipient = ?1") + fun markAllAsUnread(recipient: UserAccount) + + @Query("UPDATE Notification n SET n.unread = false, n.markedDoneAt = NOW() WHERE n.recipient = ?1 AND n.id IN ?2") + fun markAsDone(recipient: UserAccount, notifications: Collection) + + @Query("UPDATE Notification n SET n.unread = false, n.markedDoneAt = NOW() WHERE n.recipient = ?1") + fun markAllAsDone(recipient: UserAccount) + + @Query("UPDATE Notification n SET n.markedDoneAt = null WHERE n.recipient = ?1 AND n.id IN ?2") + fun unmarkAsDone(recipient: UserAccount, notifications: Collection) + + @Query("DELETE FROM notifications WHERE marked_done_at < NOW() - INTERVAL '30 DAY'", nativeQuery = true) + fun pruneOldNotifications() // Native query since HQL can't do "INTERVAL" +} From 1ec0527d0636f07f8ba196d846c4dee99f152a05 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Sun, 19 Nov 2023 11:12:02 +0100 Subject: [PATCH 02/44] chore: cleanup batch job internal events --- .../io/tolgee/batch/BatchJobActionService.kt | 2 -- .../batch/BatchJobConcurrentLauncher.kt | 2 +- .../kotlin/io/tolgee/batch/ProgressManager.kt | 8 ++----- .../batch/events/OnBatchJobFinalized.kt | 8 ------- .../tolgee/batch/events/OnBatchJobStarted.kt | 21 +++++++++++++++++++ .../batch/events/OnBatchJobStatusUpdated.kt | 9 -------- 6 files changed, 24 insertions(+), 26 deletions(-) delete mode 100644 backend/data/src/main/kotlin/io/tolgee/batch/events/OnBatchJobFinalized.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/batch/events/OnBatchJobStarted.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/batch/events/OnBatchJobStatusUpdated.kt diff --git a/backend/data/src/main/kotlin/io/tolgee/batch/BatchJobActionService.kt b/backend/data/src/main/kotlin/io/tolgee/batch/BatchJobActionService.kt index 537f72ce05..5f741e65f5 100644 --- a/backend/data/src/main/kotlin/io/tolgee/batch/BatchJobActionService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/batch/BatchJobActionService.kt @@ -47,7 +47,6 @@ class BatchJobActionService( private val savePointManager: SavePointManager, private val currentDateProvider: CurrentDateProvider, private val activityHolder: ActivityHolder, - private val batchJobProjectLockingManager: BatchJobProjectLockingManager, private val metrics: Metrics ) : Logging { companion object { @@ -56,7 +55,6 @@ class BatchJobActionService( @EventListener(ApplicationReadyEvent::class) fun run() { - println("Application ready") executeInNewTransaction(transactionManager) { batchJobChunkExecutionQueue.populateQueue() } diff --git a/backend/data/src/main/kotlin/io/tolgee/batch/BatchJobConcurrentLauncher.kt b/backend/data/src/main/kotlin/io/tolgee/batch/BatchJobConcurrentLauncher.kt index b3d4b1815a..f7c18e8490 100644 --- a/backend/data/src/main/kotlin/io/tolgee/batch/BatchJobConcurrentLauncher.kt +++ b/backend/data/src/main/kotlin/io/tolgee/batch/BatchJobConcurrentLauncher.kt @@ -207,7 +207,7 @@ class BatchJobConcurrentLauncher( } private fun addBackToQueue(executionItem: ExecutionQueueItem) { - logger.trace("Adding execution $executionItem back to queue") + logger.trace("Adding execution {} back to queue", executionItem) batchJobChunkExecutionQueue.addItemsToLocalQueue(listOf(executionItem)) } diff --git a/backend/data/src/main/kotlin/io/tolgee/batch/ProgressManager.kt b/backend/data/src/main/kotlin/io/tolgee/batch/ProgressManager.kt index 516d1a2ae7..f97bd50c87 100644 --- a/backend/data/src/main/kotlin/io/tolgee/batch/ProgressManager.kt +++ b/backend/data/src/main/kotlin/io/tolgee/batch/ProgressManager.kt @@ -1,11 +1,7 @@ package io.tolgee.batch import io.tolgee.batch.data.BatchJobDto -import io.tolgee.batch.events.OnBatchJobCancelled -import io.tolgee.batch.events.OnBatchJobFailed -import io.tolgee.batch.events.OnBatchJobProgress -import io.tolgee.batch.events.OnBatchJobStatusUpdated -import io.tolgee.batch.events.OnBatchJobSucceeded +import io.tolgee.batch.events.* import io.tolgee.batch.state.BatchJobStateProvider import io.tolgee.batch.state.ExecutionState import io.tolgee.constants.Message @@ -115,7 +111,6 @@ class ProgressManager( private fun onJobCompletedCommitted(execution: BatchJobChunkExecution) { batchJobStateProvider.removeJobState(execution.batchJob.id) val jobDto = batchJobService.getJobDto(execution.batchJob.id) - eventPublisher.publishEvent(OnBatchJobStatusUpdated(jobDto.id, jobDto.projectId, jobDto.status)) cachingBatchJobService.evictJobCache(execution.batchJob.id) batchJobProjectLockingManager.unlockJobForProject(jobDto.projectId, jobDto.id) batchJobStateProvider.removeJobState(execution.batchJob.id) @@ -187,6 +182,7 @@ class ProgressManager( if (job.status == BatchJobStatus.PENDING) { logger.debug("""Updating job state to running ${job.id}""") cachingBatchJobService.setRunningState(job.id) + eventPublisher.publishEvent(OnBatchJobStarted(job)) } } } diff --git a/backend/data/src/main/kotlin/io/tolgee/batch/events/OnBatchJobFinalized.kt b/backend/data/src/main/kotlin/io/tolgee/batch/events/OnBatchJobFinalized.kt deleted file mode 100644 index f73554f866..0000000000 --- a/backend/data/src/main/kotlin/io/tolgee/batch/events/OnBatchJobFinalized.kt +++ /dev/null @@ -1,8 +0,0 @@ -package io.tolgee.batch.events - -import io.tolgee.batch.OnBatchJobCompleted -import io.tolgee.batch.data.BatchJobDto - -data class OnBatchJobFinalized( - override val job: BatchJobDto, -) : OnBatchJobCompleted diff --git a/backend/data/src/main/kotlin/io/tolgee/batch/events/OnBatchJobStarted.kt b/backend/data/src/main/kotlin/io/tolgee/batch/events/OnBatchJobStarted.kt new file mode 100644 index 0000000000..b12f8a0443 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/batch/events/OnBatchJobStarted.kt @@ -0,0 +1,21 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.batch.events + +import io.tolgee.batch.data.BatchJobDto + +data class OnBatchJobStarted(val job: BatchJobDto) diff --git a/backend/data/src/main/kotlin/io/tolgee/batch/events/OnBatchJobStatusUpdated.kt b/backend/data/src/main/kotlin/io/tolgee/batch/events/OnBatchJobStatusUpdated.kt deleted file mode 100644 index ec309c0fb6..0000000000 --- a/backend/data/src/main/kotlin/io/tolgee/batch/events/OnBatchJobStatusUpdated.kt +++ /dev/null @@ -1,9 +0,0 @@ -package io.tolgee.batch.events - -import io.tolgee.model.batch.BatchJobStatus - -class OnBatchJobStatusUpdated( - val jobId: Long, - val projectId: Long, - val status: BatchJobStatus -) From eefcec0e786d0952bc89fe7bd7af34f4c3160ef7 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Sun, 19 Nov 2023 13:34:14 +0100 Subject: [PATCH 03/44] feat: core user notification dispatch --- .../app/src/main/resources/application.yaml | 5 +- .../data/NotificationsTestData.kt | 290 ++++++++++++++++++ .../postgres/CustomPostgreSQLDialect.kt | 2 +- .../io/tolgee/dtos/ComputedPermissionDto.kt | 4 +- .../kotlin/io/tolgee/model/Notification.kt | 76 +++-- .../main/kotlin/io/tolgee/model/Permission.kt | 1 + .../UserAccountProjectPermissionDataView.kt | 35 +++ .../notifications/NotificationService.kt | 54 ++-- .../dispatchers/UserNotificationDispatch.kt | 153 +++++++++ .../dto/NotificationCreateDto.kt | 58 ++++ .../events/NotificationCreateEvent.kt | 24 ++ .../NotificationUserPushEvent.kt} | 7 +- .../listeners/ActivityEventListener.kt | 43 +-- .../listeners/BatchJobListener.kt | 138 +++++++-- .../tolgee/repository/LanguageRepository.kt | 10 + .../repository/NotificationsRepository.kt | 17 +- .../repository/UserAccountRepository.kt | 44 ++- .../io/tolgee/service/LanguageService.kt | 4 + .../service/security/PermissionService.kt | 33 ++ .../service/security/UserAccountService.kt | 12 + .../main/resources/db/changelog/schema.xml | 54 ++++ .../NotificationsE2eDataController.kt | 41 +++ 22 files changed, 1004 insertions(+), 101 deletions(-) create mode 100644 backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationsTestData.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionDataView.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationCreateEvent.kt rename backend/data/src/main/kotlin/io/tolgee/notifications/{NotificationPushEvent.kt => events/NotificationUserPushEvent.kt} (78%) create mode 100644 backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2e_data/NotificationsE2eDataController.kt diff --git a/backend/app/src/main/resources/application.yaml b/backend/app/src/main/resources/application.yaml index 780713c1b5..a409ecb6f1 100644 --- a/backend/app/src/main/resources/application.yaml +++ b/backend/app/src/main/resources/application.yaml @@ -13,7 +13,8 @@ spring: properties: hibernate: jdbc: - batch_size: 1000 + batch_size: 50 + batch_versioned_data: true order_inserts: true order_updates: true dialect: io.tolgee.dialects.postgres.CustomPostgreSQLDialect @@ -25,6 +26,8 @@ spring: enabled: false jdbc: initialize-schema: always + datasource: + auto-commit: false # main: # lazy-initialization: true tolgee: diff --git a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationsTestData.kt b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationsTestData.kt new file mode 100644 index 0000000000..94f5395dad --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationsTestData.kt @@ -0,0 +1,290 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.development.testDataBuilder.data + +import io.tolgee.development.testDataBuilder.builders.TestDataBuilder +import io.tolgee.model.Organization +import io.tolgee.model.Project +import io.tolgee.model.UserAccount +import io.tolgee.model.enums.OrganizationRoleType +import io.tolgee.model.enums.ProjectPermissionType +import io.tolgee.model.enums.Scope +import io.tolgee.model.enums.TranslationState +import io.tolgee.model.key.Key +import io.tolgee.model.translation.Translation + +class NotificationsTestData { + lateinit var admin: UserAccount + + lateinit var orgAdmin: UserAccount + lateinit var projectManager: UserAccount + lateinit var frenchTranslator: UserAccount + lateinit var czechTranslator: UserAccount + lateinit var germanTranslator: UserAccount + lateinit var frenchCzechTranslator: UserAccount + + lateinit var bob: UserAccount + lateinit var alice: UserAccount + + lateinit var acme: Organization + + lateinit var project1: Project + lateinit var project2: Project + + lateinit var keyProject1: Key + lateinit var key1EnTranslation: Translation + lateinit var key1FrTranslation: Translation + lateinit var key1CzTranslation: Translation + + lateinit var keyProject2: Key + lateinit var key2EnTranslation: Translation + + val root: TestDataBuilder = TestDataBuilder() + + init { + root.apply { + addUserAccount { + name = "Admin" + username = "admin" + isInitialUser = true + role = UserAccount.Role.ADMIN + + admin = this + } + + addUserAccountWithoutOrganization { + name = "Acme 1 chief" + username = "chief-acme-1" + + orgAdmin = this + } + + addUserAccountWithoutOrganization { + name = "Project manager" + username = "project-manager" + + projectManager = this + } + + addUserAccountWithoutOrganization { + name = "Translator (french)" + username = "french-translator" + + frenchTranslator = this + } + + addUserAccountWithoutOrganization { + name = "Translator (czech)" + username = "czech-translator" + + czechTranslator = this + } + + addUserAccountWithoutOrganization { + name = "Translator (german)" + username = "german-translator" + + germanTranslator = this + } + + addUserAccountWithoutOrganization { + name = "Translator (french and czech)" + username = "french-czech-translator" + + frenchCzechTranslator = this + } + + addUserAccount { + name = "Bob" + username = "bob" + + bob = this + } + + addUserAccount { + name = "Alice" + username = "alice" + + alice = this + } + + addOrganization { + name = "ACME Corporation" + slug = "acme" + + this@NotificationsTestData.acme = this@addOrganization + }.build { + addRole { + user = orgAdmin + type = OrganizationRoleType.OWNER + } + + addRole { + user = projectManager + type = OrganizationRoleType.MEMBER + } + + addRole { + user = frenchTranslator + type = OrganizationRoleType.MEMBER + } + + addRole { + user = czechTranslator + type = OrganizationRoleType.MEMBER + } + + addRole { + user = germanTranslator + type = OrganizationRoleType.MEMBER + } + + addRole { + user = frenchCzechTranslator + type = OrganizationRoleType.MEMBER + } + + addProject { + name = "Explosive Type-Checker" + slug = "explosive-type-checker" + organizationOwner = acme + + project1 = this + }.build { + val en = addEnglish() + val fr = addFrench() + val cz = addCzech() + val de = addGerman() + + val key = addKey { + name = "some-key" + + this@NotificationsTestData.keyProject1 = this@addKey + } + + addTranslation { + this.key = key.self + language = en.self + text = "Some translation" + state = TranslationState.REVIEWED + + this@NotificationsTestData.key1EnTranslation = this@addTranslation + } + + addTranslation { + this.key = key.self + language = fr.self + text = "Some french translation" + state = TranslationState.REVIEWED + + this@NotificationsTestData.key1FrTranslation = this@addTranslation + } + + addTranslation { + this.key = key.self + language = cz.self + text = "Some czech translation" + + this@NotificationsTestData.key1CzTranslation = this@addTranslation + } + + // --- --- --- + + addPermission { + user = frenchTranslator + scopes = ProjectPermissionType.REVIEW.availableScopes + viewLanguages.add(en.self) + viewLanguages.add(fr.self) + translateLanguages.add(en.self) + translateLanguages.add(fr.self) + stateChangeLanguages.add(en.self) + stateChangeLanguages.add(fr.self) + } + + addPermission { + user = czechTranslator + scopes = ProjectPermissionType.REVIEW.availableScopes + viewLanguages.add(en.self) + viewLanguages.add(cz.self) + translateLanguages.add(en.self) + translateLanguages.add(cz.self) + stateChangeLanguages.add(en.self) + stateChangeLanguages.add(cz.self) + } + + addPermission { + user = germanTranslator + scopes = ProjectPermissionType.REVIEW.availableScopes + viewLanguages.add(en.self) + viewLanguages.add(de.self) + translateLanguages.add(en.self) + translateLanguages.add(de.self) + stateChangeLanguages.add(en.self) + stateChangeLanguages.add(de.self) + } + + addPermission { + user = frenchCzechTranslator + scopes = ProjectPermissionType.REVIEW.availableScopes + viewLanguages.add(en.self) + viewLanguages.add(fr.self) + viewLanguages.add(cz.self) + translateLanguages.add(en.self) + translateLanguages.add(fr.self) + translateLanguages.add(cz.self) + stateChangeLanguages.add(en.self) + stateChangeLanguages.add(fr.self) + stateChangeLanguages.add(cz.self) + } + + addPermission { + user = bob + scopes = arrayOf(Scope.TRANSLATIONS_EDIT) + } + } + + addProject { + name = "Rocket-Powered Office Chair Controller" + slug = "rpocc" + organizationOwner = acme + + project2 = this + }.build { + val en = addEnglish() + val key = addKey { + name = "some-key" + + this@NotificationsTestData.keyProject2 = this@addKey + } + + addTranslation { + this.key = key.self + language = en.self + text = "Some translation" + + this@NotificationsTestData.key2EnTranslation = this@addTranslation + } + + addPermission { + user = alice + scopes = arrayOf(Scope.TRANSLATIONS_EDIT, Scope.SCREENSHOTS_UPLOAD) + } + } + } + } + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/dialects/postgres/CustomPostgreSQLDialect.kt b/backend/data/src/main/kotlin/io/tolgee/dialects/postgres/CustomPostgreSQLDialect.kt index 9c8e7e18d4..1393577a87 100644 --- a/backend/data/src/main/kotlin/io/tolgee/dialects/postgres/CustomPostgreSQLDialect.kt +++ b/backend/data/src/main/kotlin/io/tolgee/dialects/postgres/CustomPostgreSQLDialect.kt @@ -14,7 +14,7 @@ import java.sql.Types @Suppress("unused") class CustomPostgreSQLDialect : PostgreSQL10Dialect() { init { - registerHibernateType(2003, StringArrayType::class.java.name) + registerHibernateType(Types.ARRAY, StringArrayType::class.java.name) } override fun renderOrderByElement( diff --git a/backend/data/src/main/kotlin/io/tolgee/dtos/ComputedPermissionDto.kt b/backend/data/src/main/kotlin/io/tolgee/dtos/ComputedPermissionDto.kt index a2c9e88144..216d8077fa 100644 --- a/backend/data/src/main/kotlin/io/tolgee/dtos/ComputedPermissionDto.kt +++ b/backend/data/src/main/kotlin/io/tolgee/dtos/ComputedPermissionDto.kt @@ -72,7 +72,7 @@ class ComputedPermissionDto( ) companion object { - private fun getEmptyPermission(scopes: Array, type: ProjectPermissionType): IPermission { + fun getEmptyPermission(scopes: Array, type: ProjectPermissionType?): IPermission { return object : IPermission { override val scopes: Array get() = scopes @@ -86,7 +86,7 @@ class ComputedPermissionDto( get() = null override val stateChangeLanguageIds: Set? get() = null - override val type: ProjectPermissionType + override val type: ProjectPermissionType? get() = type override val granular: Boolean? get() = null diff --git a/backend/data/src/main/kotlin/io/tolgee/model/Notification.kt b/backend/data/src/main/kotlin/io/tolgee/model/Notification.kt index 5e47be121b..096145acb3 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/Notification.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/Notification.kt @@ -16,60 +16,90 @@ package io.tolgee.model +import com.vladmihalcea.hibernate.type.json.JsonBinaryType import io.tolgee.model.activity.ActivityRevision import io.tolgee.model.batch.BatchJob -import org.hibernate.annotations.Check -import org.hibernate.annotations.CreationTimestamp +import org.hibernate.annotations.ColumnDefault +import org.hibernate.annotations.Type +import org.hibernate.annotations.TypeDef +import org.hibernate.annotations.TypeDefs import org.hibernate.annotations.UpdateTimestamp import java.util.* import javax.persistence.* @Entity +@TypeDefs( + value = [ + TypeDef(name = "jsonb", typeClass = JsonBinaryType::class) + ] +) class Notification private constructor( @Column(nullable = false) @Enumerated(EnumType.STRING) val type: NotificationType, - @ManyToOne(fetch = FetchType.EAGER, cascade = [ CascadeType.ALL ]) // We most definitely need this to show the notification: eager + @ManyToOne(fetch = FetchType.LAZY, cascade = [ CascadeType.REMOVE ]) // This data is very likely to be useless: lazy + @JoinColumn(nullable = false) + val recipient: UserAccount, + + @ManyToOne(fetch = FetchType.EAGER, cascade = [ CascadeType.REMOVE ]) // We most definitely need this to show the notification: eager @JoinColumn(nullable = false) val project: Project, - @Check(constraints = "activity_revision IS NULL OR type == \"ACTIVITY\"") - @ManyToMany(fetch = FetchType.EAGER, cascade = [ CascadeType.ALL ]) // We most definitely need this to show the notification: eager + @ManyToMany(fetch = FetchType.EAGER, cascade = [ CascadeType.REMOVE ]) // We most definitely need this to show the notification: eager @JoinTable(name = "notification_activity_revisions") val activityRevisions: MutableList? = null, - @Check(constraints = "batch_job IS NULL OR type == \"BATCH_JOB_FAILURE\"") - @ManyToOne(fetch = FetchType.EAGER, cascade = [ CascadeType.ALL ]) // We most definitely need this to show the notification: eager - @Column(name = "batch_job") + @ManyToOne(fetch = FetchType.EAGER, cascade = [ CascadeType.REMOVE ]) // We most definitely need this to show the notification: eager val batchJob: BatchJob? = null, + + @Type(type = "jsonb") + val meta: MutableMap ) { @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) + @SequenceGenerator(name = "notification_seq", sequenceName = "sequence_notifications") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "notification_seq") val id: Long = 0 @Column(nullable = false) - var unread: Boolean = false - - // It is a `lateinit` since during notification creation, the user is provided externally. - // However, because it's non-nullable in DB it'll never actually be `null` besides during creation. - // It allows not polluting the entire code with a nullable type. - @ManyToOne(fetch = FetchType.LAZY, cascade = [ CascadeType.ALL ]) // This data is very likely to be useless: lazy - @JoinColumn(nullable = false) - lateinit var recipient: UserAccount + @ColumnDefault("true") + var unread: Boolean = true + @Temporal(TemporalType.TIMESTAMP) var markedDoneAt: Date? = null - @CreationTimestamp - @UpdateTimestamp @OrderBy + @UpdateTimestamp + @Temporal(TemporalType.TIMESTAMP) val lastUpdated: Date = Date() - constructor(project: Project, activityRevision: ActivityRevision) : - this(NotificationType.ACTIVITY, project, activityRevisions = mutableListOf(activityRevision)) + constructor( + recipient: UserAccount, + project: Project, + activityRevision: ActivityRevision, + meta: Map? = null, + ) : + this( + NotificationType.ACTIVITY, + recipient, + project, + activityRevisions = mutableListOf(activityRevision), + meta = meta?.toMutableMap() ?: mutableMapOf(), + ) - constructor(project: Project, batchJob: BatchJob) : - this(NotificationType.BATCH_JOB_FAILURE, project, batchJob = batchJob) + constructor( + recipient: UserAccount, + project: Project, + batchJob: BatchJob, + meta: Map? = null, + ) : + this( + NotificationType.BATCH_JOB_FAILURE, + recipient, + project, + batchJob = batchJob, + meta = meta?.toMutableMap() ?: mutableMapOf(), + ) enum class NotificationType { ACTIVITY, diff --git a/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt b/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt index 7e0aa3cacd..e8c15f965e 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt @@ -94,6 +94,7 @@ class Permission( * When specified, user is restricted to edit specific language translations. */ @ManyToMany(fetch = FetchType.EAGER) + @JoinTable(name = "permission_view_languages") var viewLanguages: MutableSet = mutableSetOf() /** diff --git a/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionDataView.kt b/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionDataView.kt new file mode 100644 index 0000000000..fce02785b0 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionDataView.kt @@ -0,0 +1,35 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.model.views + +import io.tolgee.model.enums.OrganizationRoleType +import io.tolgee.model.enums.ProjectPermissionType +import io.tolgee.model.enums.Scope + +class UserAccountProjectPermissionDataView( + val id: Long, + val projectId: Long, + val organizationRole: OrganizationRoleType?, + val basePermissionsBasic: ProjectPermissionType?, + basePermissionsGranular: Array>?, + val permissionsBasic: ProjectPermissionType?, + permissionsGranular: Array>?, +) { + // I hate Hibernate - it *requires* an Array> or complains... + val basePermissionsGranular: List? = basePermissionsGranular?.map { enumValueOf(it.name) } + val permissionsGranular: List? = permissionsGranular?.map { enumValueOf(it.name) } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationService.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationService.kt index 967c4a5b0a..93783702b8 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationService.kt @@ -18,6 +18,8 @@ package io.tolgee.notifications import io.tolgee.model.Notification import io.tolgee.model.UserAccount +import io.tolgee.notifications.dto.NotificationCreateDto +import io.tolgee.notifications.events.NotificationUserPushEvent import io.tolgee.repository.NotificationsRepository import org.springframework.context.ApplicationEventPublisher import org.springframework.data.domain.Pageable @@ -25,50 +27,40 @@ import org.springframework.scheduling.annotation.Async import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import java.util.EnumSet +import javax.persistence.EntityManager @Service class NotificationService( private val notificationsRepository: NotificationsRepository, private val applicationEventPublisher: ApplicationEventPublisher, + private val entityManager: EntityManager, ) { @Async @Transactional - fun dispatchNotification(notification: Notification, user: UserAccount) = - dispatchNotification(notification, setOf(user)) + fun dispatchNotificationToUserId(notificationDto: NotificationCreateDto, user: Long) { + val userReference = entityManager.getReference(UserAccount::class.java, user) + return dispatchNotificationToUser(notificationDto, userReference) + } @Async @Transactional - fun dispatchNotification(notification: Notification, users: Set) { - val localUsers = users.toMutableSet() - val notificationObjects = mutableSetOf() - - if (debouncedNotificationTypes.contains(notification.type)) { - val existingNotifications = notificationsRepository.findAllByUnreadTrueAndTypeAndProjectAndRecipientIn( - notification.type, - notification.project, - users, - ) - - existingNotifications.forEach { - localUsers.remove(it.recipient) + fun dispatchNotificationToUserIds(notificationDto: NotificationCreateDto, users: List) { + val usersReferences = users.map { entityManager.getReference(UserAccount::class.java, it) } + dispatchNotificationToUsers(notificationDto, usersReferences) + } - when (notification.type) { - Notification.NotificationType.ACTIVITY -> - it.activityRevisions!!.addAll(notification.activityRevisions!!) - else -> - throw RuntimeException("Cannot debounce notification type ${notification.type}") - } - } + @Async + @Transactional + fun dispatchNotificationToUser(notificationDto: NotificationCreateDto, user: UserAccount) = + dispatchNotificationToUsers(notificationDto, listOf(user)) - // Push modifications - notificationObjects.addAll( - notificationsRepository.saveAll(existingNotifications) - ) - } + @Async + @Transactional + fun dispatchNotificationToUsers(notificationDto: NotificationCreateDto, users: List) { + val notificationObjects = mutableSetOf() - // Create notifications - localUsers.forEach { - notification.recipient = it + users.forEach { + val notification = notificationDto.toNotificationEntity(it) notificationObjects.add( notificationsRepository.save(notification) ) @@ -76,7 +68,7 @@ class NotificationService( // Dispatch event applicationEventPublisher.publishEvent( - NotificationPushEvent(notificationObjects) + NotificationUserPushEvent(notificationObjects) ) } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt new file mode 100644 index 0000000000..57d4ea4395 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt @@ -0,0 +1,153 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.notifications.dispatchers + +import io.tolgee.activity.ModifiedEntitiesType +import io.tolgee.activity.data.ActivityType +import io.tolgee.events.OnProjectActivityEvent +import io.tolgee.model.Project +import io.tolgee.model.activity.ActivityRevision +import io.tolgee.model.batch.BatchJobStatus +import io.tolgee.model.enums.Scope +import io.tolgee.model.translation.Translation +import io.tolgee.notifications.NotificationService +import io.tolgee.notifications.dto.NotificationCreateDto +import io.tolgee.notifications.events.NotificationCreateEvent +import io.tolgee.service.LanguageService +import io.tolgee.service.security.PermissionService +import io.tolgee.service.security.UserAccountService +import io.tolgee.util.Logging +import io.tolgee.util.logger +import org.springframework.context.ApplicationEventPublisher +import org.springframework.context.event.EventListener +import org.springframework.stereotype.Component +import javax.persistence.EntityManager + +@Component +class UserNotificationDispatch( + private val userAccountService: UserAccountService, + private val permissionService: PermissionService, + private val languageService: LanguageService, + private val notificationService: NotificationService, +) : Logging { + @EventListener + fun onNotificationCreate(e: NotificationCreateEvent) { + logger.trace("Received notification creation event {}", e) + + when { + e.notification.activityRevision != null -> handleActivityNotification(e) + e.notification.batchJob != null -> handleBatchJobNotification(e) + else -> logger.warn("Encountered invalid notification create event {}", e) + } + } + + private fun handleActivityNotification(e: NotificationCreateEvent) { + val revision = e.notification.activityRevision!! + val users = getUsersConcernedByRevision(revision) + if (users.isEmpty()) return + + notificationService.dispatchNotificationToUserIds(e.notification, users) + } + + private fun handleBatchJobNotification(e: NotificationCreateEvent) { + // Only send a full notification for job failures. The rest will be ephemeral WebSocket based. + if (e.notification.meta["status"] != BatchJobStatus.FAILED) return + + val batchJob = e.notification.batchJob!! + val author = batchJob.author ?: return + notificationService.dispatchNotificationToUser(e.notification, author) + } + + private fun getUsersConcernedByRevision(revision: ActivityRevision): List { + return when (revision.type) { + ActivityType.CREATE_LANGUAGE, + ActivityType.KEY_TAGS_EDIT, + ActivityType.KEY_NAME_EDIT, + ActivityType.CREATE_KEY, + ActivityType.NAMESPACE_EDIT, + ActivityType.BATCH_TAG_KEYS, + ActivityType.BATCH_UNTAG_KEYS, + ActivityType.BATCH_SET_KEYS_NAMESPACE + -> getAllUsersOfProject(revision) + + ActivityType.SET_TRANSLATION_STATE, + ActivityType.SET_TRANSLATIONS, + ActivityType.DISMISS_AUTO_TRANSLATED_STATE, + ActivityType.SET_OUTDATED_FLAG, + ActivityType.TRANSLATION_COMMENT_ADD, + ActivityType.TRANSLATION_COMMENT_EDIT, + ActivityType.TRANSLATION_COMMENT_SET_STATE, + ActivityType.BATCH_PRE_TRANSLATE_BY_TM, + ActivityType.BATCH_MACHINE_TRANSLATE, + ActivityType.AUTO_TRANSLATE, + ActivityType.BATCH_CLEAR_TRANSLATIONS, + ActivityType.BATCH_COPY_TRANSLATIONS, + ActivityType.BATCH_SET_TRANSLATION_STATE + -> getUsersConcernedByTranslationChange(revision) + + ActivityType.SCREENSHOT_ADD + -> getUsersConcernedByScreenshotChange(revision) + + ActivityType.IMPORT -> TODO() + ActivityType.COMPLEX_EDIT -> TODO() + + // Do not show a notification about those type of events + ActivityType.EDIT_PROJECT, + ActivityType.EDIT_LANGUAGE, + ActivityType.DELETE_LANGUAGE, + ActivityType.KEY_DELETE, + ActivityType.TRANSLATION_COMMENT_DELETE, + ActivityType.SCREENSHOT_DELETE, + ActivityType.CREATE_PROJECT, + ActivityType.UNKNOWN, + null -> emptyList() + } + } + + private fun getAllUsersOfProject(activityRevision: ActivityRevision): List { + return userAccountService.getAllPermissionInformationOfPermittedUsersInProject(activityRevision.projectId!!) + .map { it.id } + } + + private fun getUsersConcernedByScreenshotChange(activityRevision: ActivityRevision): List { + return userAccountService.getAllPermissionInformationOfPermittedUsersInProject(activityRevision.projectId!!) + .filter { + val computedPermissions = permissionService.computeProjectPermission(it) + computedPermissions.expandedScopes.contains(Scope.SCREENSHOTS_VIEW) + } + .map { it.id } + } + + private fun getUsersConcernedByTranslationChange(activityRevision: ActivityRevision): List { + val translationIds = activityRevision.modifiedEntities + .filter { it.entityClass == Translation::class.simpleName } + .map { it.entityId } + + val langIds = languageService.findLanguageIdsOfTranslations(translationIds) + return userAccountService.getAllPermissionInformationOfPermittedUsersInProject( + activityRevision.projectId!!, + langIds + ) + .filter { + val computedPermissions = permissionService.computeProjectPermission(it) + println("--") + println(computedPermissions.expandedScopes.joinToString(", ")) + computedPermissions.expandedScopes.contains(Scope.TRANSLATIONS_VIEW) + } + .map { it.id } + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt new file mode 100644 index 0000000000..a988d97d62 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt @@ -0,0 +1,58 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.notifications.dto + +import io.tolgee.model.Notification +import io.tolgee.model.Project +import io.tolgee.model.UserAccount +import io.tolgee.model.activity.ActivityRevision +import io.tolgee.model.batch.BatchJob + +data class NotificationCreateDto( + val project: Project, + val activityRevision: ActivityRevision? = null, + val batchJob: BatchJob? = null, +) { + val meta: MutableMap = mutableMapOf() + + constructor(project: Project, activityRevision: ActivityRevision): + this(project, activityRevision = activityRevision, batchJob = null) + + constructor(project: Project, batchJob: BatchJob): + this(project, activityRevision = null, batchJob = batchJob) + + init { + if (activityRevision == null && batchJob == null) { + throw IllegalArgumentException("No entity attached to the notification") + } + + if (activityRevision != null && batchJob != null) { + throw IllegalArgumentException("Too many entities attached to the notification") + } + } + + fun toNotificationEntity(user: UserAccount): Notification { + return when { + activityRevision != null -> + Notification(user, project, activityRevision, meta) + batchJob != null -> + Notification(user, project, batchJob, meta) + else -> + throw IllegalStateException("No entity attached to this DTO??") + } + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationCreateEvent.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationCreateEvent.kt new file mode 100644 index 0000000000..968bf0e2fb --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationCreateEvent.kt @@ -0,0 +1,24 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.notifications.events + +import io.tolgee.notifications.dto.NotificationCreateDto + +data class NotificationCreateEvent( + val notification: NotificationCreateDto, + val source: Any? = null +) diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPushEvent.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationUserPushEvent.kt similarity index 78% rename from backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPushEvent.kt rename to backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationUserPushEvent.kt index f2592b453e..041bcf5988 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPushEvent.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationUserPushEvent.kt @@ -14,8 +14,11 @@ * limitations under the License. */ -package io.tolgee.notifications +package io.tolgee.notifications.events import io.tolgee.model.Notification -data class NotificationPushEvent(val notifications: Set) +/** + * Event sent when a set of users received a new notification. + */ +data class NotificationUserPushEvent(val notifications: Set) diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt index be39437a19..eb8833f5c2 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt @@ -17,34 +17,41 @@ package io.tolgee.notifications.listeners import io.tolgee.events.OnProjectActivityStoredEvent -import io.tolgee.model.Notification -import io.tolgee.model.UserAccount -import io.tolgee.model.activity.ActivityRevision -import io.tolgee.notifications.NotificationService -import io.tolgee.service.project.ProjectService +import io.tolgee.model.Project +import io.tolgee.notifications.dto.NotificationCreateDto +import io.tolgee.notifications.events.NotificationCreateEvent +import io.tolgee.util.Logging +import io.tolgee.util.logger +import org.springframework.context.ApplicationEventPublisher import org.springframework.context.event.EventListener import org.springframework.stereotype.Component +import javax.persistence.EntityManager @Component class ActivityEventListener( - private val projectService: ProjectService, - private val notificationService: NotificationService, -) { + private val applicationEventPublisher: ApplicationEventPublisher, + private val entityManager: EntityManager, +) : Logging { @EventListener fun onActivityRevision(e: OnProjectActivityStoredEvent) { - val id = e.activityRevision.projectId ?: return + // Using the Stored variant so `modifiedEntities` is populated. - val users = getUsersConcernedByRevision(e.activityRevision) - val notification = Notification( - projectService.get(id), - e.activityRevision, + logger.trace( + "Received project activity event - {} on proj#{} ({} entities modified)", + e.activityRevision.type, + e.activityRevision.projectId, + e.activityRevision.modifiedEntities.size ) - notificationService.dispatchNotification(notification, users) - } + val projectId = e.activityRevision.projectId ?: return + val project = entityManager.getReference(Project::class.java, projectId) + val notificationDto = NotificationCreateDto( + project = project, + activityRevision = e.activityRevision + ) - private fun getUsersConcernedByRevision(revision: ActivityRevision): Set { - // TODO!! - return emptySet() + applicationEventPublisher.publishEvent( + NotificationCreateEvent(notificationDto, e) + ) } } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt index e16dd11ac5..c099547b02 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt @@ -17,35 +17,137 @@ package io.tolgee.notifications.listeners import io.tolgee.batch.BatchJobService -import io.tolgee.batch.events.OnBatchJobFailed -import io.tolgee.model.Notification -import io.tolgee.notifications.NotificationService -import io.tolgee.service.project.ProjectService -import io.tolgee.service.security.UserAccountService +import io.tolgee.batch.data.BatchJobDto +import io.tolgee.batch.events.* +import io.tolgee.model.Project +import io.tolgee.model.batch.BatchJob +import io.tolgee.model.batch.BatchJobStatus +import io.tolgee.notifications.dto.NotificationCreateDto +import io.tolgee.notifications.events.NotificationCreateEvent +import io.tolgee.util.Logging +import io.tolgee.util.logger +import org.springframework.context.ApplicationEventPublisher import org.springframework.context.event.EventListener import org.springframework.stereotype.Component +import javax.persistence.EntityManager @Component class BatchJobListener( - private val userAccountService: UserAccountService, - private val projectService: ProjectService, + private val applicationEventPublisher: ApplicationEventPublisher, + private val entityManager: EntityManager, private val batchJobService: BatchJobService, - private val notificationService: NotificationService, -) { +) : Logging { + @EventListener + fun onBatchEventQueued(e: OnBatchJobCreated) { + logger.trace( + "Received batch job created event - job#{} on proj#{}", + e.job.id, + e.job.project.id, + ) + + val notification = createNotificationBase(e.job) + notification.meta["status"] = BatchJobStatus.PENDING + + applicationEventPublisher.publishEvent( + NotificationCreateEvent(notification, e) + ) + } + + @EventListener + fun onBatchEventStarted(e: OnBatchJobStarted) { + logger.trace( + "Received batch job started event - job#{} on proj#{}", + e.job.id, + e.job.projectId, + ) + + val notification = createNotificationBase(e.job) + notification.meta["status"] = BatchJobStatus.RUNNING + notification.meta["processed"] = 0 + notification.meta["total"] = e.job.totalChunks + + applicationEventPublisher.publishEvent( + NotificationCreateEvent(notification, e) + ) + } + + @EventListener + fun onBatchEventProgress(e: OnBatchJobProgress) { + logger.trace( + "Received batch job progress event - job#{} on proj#{} ({}/{})", + e.job.id, + e.job.projectId, + e.processed, + e.total, + ) + + val notification = createNotificationBase(e.job) + notification.meta["status"] = BatchJobStatus.RUNNING + notification.meta["processed"] = e.processed + notification.meta["total"] = e.total + + applicationEventPublisher.publishEvent( + NotificationCreateEvent(notification, e) + ) + } + + @EventListener + fun onBatchEventSuccess(e: OnBatchJobSucceeded) { + logger.trace( + "Received batch job success event - job#{} on proj#{}", + e.job.id, + e.job.projectId, + ) + + val notification = createNotificationBase(e.job) + notification.meta["status"] = BatchJobStatus.SUCCESS + + applicationEventPublisher.publishEvent( + NotificationCreateEvent(notification, e) + ) + } + + @EventListener + fun onBatchEventSuccess(e: OnBatchJobCancelled) { + logger.trace( + "Received batch job cancel event - job#{} on proj#{}", + e.job.id, + e.job.projectId, + ) + + val notification = createNotificationBase(e.job) + notification.meta["status"] = BatchJobStatus.CANCELLED + + applicationEventPublisher.publishEvent( + NotificationCreateEvent(notification, e) + ) + } + @EventListener fun onBatchJobError(e: OnBatchJobFailed) { - val userId = e.job.authorId ?: return - val projectId = e.job.projectId + logger.trace( + "Received batch job failure event - job#{} on proj#{}", + e.job.id, + e.job.projectId, + ) - val user = userAccountService.get(userId) - val project = projectService.get(projectId) - val job = batchJobService.getJobEntity(e.job.id) + val notification = createNotificationBase(e.job) + notification.meta["status"] = BatchJobStatus.FAILED - val notification = Notification( - project, - job, + applicationEventPublisher.publishEvent( + NotificationCreateEvent(notification, e) ) + } + + private fun createNotificationBase(batchJob: BatchJob): NotificationCreateDto { + return NotificationCreateDto( + project = batchJob.project, + batchJob = batchJob + ) + } - notificationService.dispatchNotification(notification, user) + private fun createNotificationBase(batchJobDto: BatchJobDto): NotificationCreateDto { + val job = batchJobService.getJobEntity(batchJobDto.id) + return createNotificationBase(job) } } diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt index fe29e2c1f4..e371c312ae 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt @@ -4,6 +4,7 @@ import io.tolgee.model.Language import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query import org.springframework.stereotype.Repository import java.util.* @@ -18,4 +19,13 @@ interface LanguageRepository : JpaRepository { fun deleteAllByProjectId(projectId: Long?) fun countByIdInAndProjectId(languageIds: Set, projectId: Long): Int fun findAllByProjectIdAndIdInOrderById(projectId: Long, languageIds: List): List + + @Query( + """ + SELECT t.language.id + FROM Translation t + WHERE t.id IN :translationIds + """ + ) + fun findLanguageIdsOfTranslations(translationIds: List): List } diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/NotificationsRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/NotificationsRepository.kt index b28cda809d..e7f58963b5 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/NotificationsRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/NotificationsRepository.kt @@ -21,44 +21,53 @@ import io.tolgee.model.Project import io.tolgee.model.UserAccount import org.springframework.data.domain.Pageable import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Modifying import org.springframework.data.jpa.repository.Query import org.springframework.stereotype.Repository @Repository interface NotificationsRepository : JpaRepository { - fun findAllByMarkedDoneAtNullAndRecipient(recipient: UserAccount, pageable: Pageable): Collection + fun findAllByMarkedDoneAtNullAndRecipient(recipient: UserAccount, pageable: Pageable): List - fun findAllByMarkedDoneAtNotNullAndRecipient(recipient: UserAccount, pageable: Pageable): Collection + fun findAllByMarkedDoneAtNotNullAndRecipient(recipient: UserAccount, pageable: Pageable): List fun findAllByUnreadTrueAndTypeAndProjectAndRecipientIn( type: Notification.NotificationType, project: Project, recipients: Collection, - ): Collection + ): List fun countNotificationsByRecipientAndUnreadTrue(recipient: UserAccount): Int + @Modifying @Query("UPDATE Notification n SET n.unread = false WHERE n.recipient = ?1 AND n.id IN ?2") fun markAsRead(recipient: UserAccount, notifications: Collection) + @Modifying @Query("UPDATE Notification n SET n.unread = false WHERE n.recipient = ?1") fun markAllAsRead(recipient: UserAccount) + @Modifying @Query("UPDATE Notification n SET n.unread = true WHERE n.recipient = ?1 AND n.id IN ?2") fun markAsUnread(recipient: UserAccount, notifications: Collection) + @Modifying @Query("UPDATE Notification n SET n.unread = true WHERE n.recipient = ?1") fun markAllAsUnread(recipient: UserAccount) + @Modifying @Query("UPDATE Notification n SET n.unread = false, n.markedDoneAt = NOW() WHERE n.recipient = ?1 AND n.id IN ?2") fun markAsDone(recipient: UserAccount, notifications: Collection) + @Modifying @Query("UPDATE Notification n SET n.unread = false, n.markedDoneAt = NOW() WHERE n.recipient = ?1") fun markAllAsDone(recipient: UserAccount) + @Modifying @Query("UPDATE Notification n SET n.markedDoneAt = null WHERE n.recipient = ?1 AND n.id IN ?2") fun unmarkAsDone(recipient: UserAccount, notifications: Collection) - @Query("DELETE FROM notifications WHERE marked_done_at < NOW() - INTERVAL '30 DAY'", nativeQuery = true) + @Modifying + @Query("DELETE FROM notifications WHERE marked_done_at < NOW() - INTERVAL '90 DAY'", nativeQuery = true) fun pruneOldNotifications() // Native query since HQL can't do "INTERVAL" } diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt index a2524c7207..c9b794d942 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt @@ -2,6 +2,7 @@ package io.tolgee.repository import io.tolgee.model.UserAccount import io.tolgee.model.views.UserAccountInProjectView +import io.tolgee.model.views.UserAccountProjectPermissionDataView import io.tolgee.model.views.UserAccountWithOrganizationRoleView import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable @@ -135,7 +136,7 @@ interface UserAccountRepository : JpaRepository { @Query( value = """ - select ua from UserAccount ua where id in (:ids) + select ua from UserAccount ua where ua.id in (:ids) """ ) fun getAllByIdsIncludingDeleted(ids: Set): MutableList @@ -153,4 +154,45 @@ interface UserAccountRepository : JpaRepository { """ ) fun findDisabled(id: Long): UserAccount + + @Query( + """ + SELECT DISTINCT new io.tolgee.model.views.UserAccountProjectPermissionDataView( + ua.id, + p.id, + org_r.type, + perm_org.type, + perm_org._scopes, + perm.type, + perm._scopes + ) + FROM UserAccount ua, Project p + LEFT JOIN OrganizationRole org_r ON + org_r.user = ua AND + org_r.organization = p.organizationOwner + LEFT JOIN Permission perm ON + perm.user = ua AND + perm.project = p + LEFT JOIN Permission perm_org ON + org_r.user = ua AND + org_r.organization = p.organizationOwner AND + perm_org.organization = p.organizationOwner + LEFT JOIN Language l ON l IN elements(perm.viewLanguages) + WHERE + p.id = :projectId AND + ua.deletedAt IS NULL AND ( + (perm._scopes IS NOT NULL AND perm._scopes != '{}') OR perm.type IS NOT NULL OR + (perm_org._scopes IS NOT NULL AND perm_org._scopes != '{}') OR perm_org.type IS NOT NULL + ) AND ( + (:languageIds) IS NULL OR + l.id IS NULL OR + l.id IN (:languageIds) + ) + """ + ) + fun findAllPermittedUsersProjectPermissionView( + projectId: Long, + languageIds: List? + ): List } + diff --git a/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt b/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt index 51e78ca6dd..77517a796b 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt @@ -163,6 +163,10 @@ class LanguageService( return languageRepository.findByNameAndProject(name, project) } + fun findLanguageIdsOfTranslations(translationIds: List): List { + return languageRepository.findLanguageIdsOfTranslations(translationIds) + } + fun deleteAllByProject(projectId: Long) { findAll(projectId).forEach { deleteLanguage(it.id) diff --git a/backend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.kt b/backend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.kt index 645dc5269d..98162d9354 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.kt @@ -21,6 +21,7 @@ import io.tolgee.model.UserAccount import io.tolgee.model.enums.OrganizationRoleType import io.tolgee.model.enums.ProjectPermissionType import io.tolgee.model.enums.Scope +import io.tolgee.model.views.UserAccountProjectPermissionDataView import io.tolgee.repository.PermissionRepository import io.tolgee.service.CachedPermissionService import io.tolgee.service.LanguageService @@ -187,6 +188,38 @@ class PermissionService( } ?: computed } + fun computeProjectPermission( + projectPermissionDataView: UserAccountProjectPermissionDataView + ): ComputedPermissionDto { + val basePermissions = ComputedPermissionDto.getEmptyPermission( + type = projectPermissionDataView.basePermissionsBasic, + scopes = projectPermissionDataView.basePermissionsGranular?.toTypedArray() + ?: projectPermissionDataView.basePermissionsBasic?.availableScopes + ?: emptyArray(), + ) + + if (projectPermissionDataView.permissionsBasic == null && projectPermissionDataView.permissionsGranular == null) { + return computeProjectPermission( + projectPermissionDataView.organizationRole, + basePermissions, + directPermission = null, + ) + } + + val directPermissions = ComputedPermissionDto.getEmptyPermission( + type = projectPermissionDataView.permissionsBasic, + scopes = projectPermissionDataView.permissionsGranular?.toTypedArray() + ?: projectPermissionDataView.permissionsBasic?.availableScopes + ?: emptyArray() + ) + + return computeProjectPermission( + projectPermissionDataView.organizationRole, + basePermissions, + directPermissions, + ) + } + fun createForInvitation( invitation: Invitation, params: CreateProjectInvitationParams diff --git a/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt b/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt index 337eac3260..e28fadd53a 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt @@ -19,6 +19,7 @@ import io.tolgee.exceptions.PermissionException import io.tolgee.model.UserAccount import io.tolgee.model.views.ExtendedUserAccountInProject import io.tolgee.model.views.UserAccountInProjectView +import io.tolgee.model.views.UserAccountProjectPermissionDataView import io.tolgee.model.views.UserAccountWithOrganizationRoleView import io.tolgee.repository.UserAccountRepository import io.tolgee.service.AvatarService @@ -301,6 +302,17 @@ class UserAccountService( } } + /** + * Returns a view of all users ids who are allowed to see at least one language of [languageIds] + * (or all permitted users if null) and their permissions. + */ + fun getAllPermissionInformationOfPermittedUsersInProject( + projectId: Long, + languageIds: List? = null, + ): List { + return userAccountRepository.findAllPermittedUsersProjectPermissionView(projectId, languageIds) + } + @Transactional @CacheEvict(cacheNames = [Caches.USER_ACCOUNTS], key = "#result.id") fun update(userAccount: UserAccount, dto: UserUpdateRequestDto): UserAccount { diff --git a/backend/data/src/main/resources/db/changelog/schema.xml b/backend/data/src/main/resources/db/changelog/schema.xml index 372e920ee6..6c4de7192b 100644 --- a/backend/data/src/main/resources/db/changelog/schema.xml +++ b/backend/data/src/main/resources/db/changelog/schema.xml @@ -2760,4 +2760,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2e_data/NotificationsE2eDataController.kt b/backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2e_data/NotificationsE2eDataController.kt new file mode 100644 index 0000000000..ac3f556a49 --- /dev/null +++ b/backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2e_data/NotificationsE2eDataController.kt @@ -0,0 +1,41 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.controllers.internal.e2e_data + +import io.swagger.v3.oas.annotations.Hidden +import io.tolgee.development.testDataBuilder.builders.TestDataBuilder +import io.tolgee.development.testDataBuilder.data.NotificationsTestData +import org.springframework.transaction.annotation.Transactional +import org.springframework.web.bind.annotation.CrossOrigin +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@RestController +@CrossOrigin(origins = ["*"]) +@Hidden +@RequestMapping(value = ["internal/e2e-data/notifications"]) +class NotificationsE2eDataController : AbstractE2eDataController() { + @GetMapping(value = ["/generate"]) + @Transactional + fun generateBasicTestData() { + testDataService.saveTestData(testData) + } + + override val testData: TestDataBuilder + get() = NotificationsTestData().root +} From c4a183ca42de820f5b4a432de6ba096a7174a42d Mon Sep 17 00:00:00 2001 From: Cynthia Date: Sun, 19 Nov 2023 13:38:31 +0100 Subject: [PATCH 04/44] chore: lint --- .../tolgee/postgresRunners/PostgresDockerRunner.kt | 3 ++- .../main/kotlin/io/tolgee/batch/ProgressManager.kt | 6 +++++- .../src/main/kotlin/io/tolgee/model/Notification.kt | 12 ++++++++---- .../views/UserAccountProjectPermissionDataView.kt | 4 ++-- .../io/tolgee/notifications/NotificationService.kt | 4 ++-- .../dispatchers/UserNotificationDispatch.kt | 6 ------ .../notifications/dto/NotificationCreateDto.kt | 4 ++-- .../notifications/listeners/BatchJobListener.kt | 1 - .../io/tolgee/repository/UserAccountRepository.kt | 1 - 9 files changed, 21 insertions(+), 20 deletions(-) diff --git a/backend/app/src/main/kotlin/io/tolgee/postgresRunners/PostgresDockerRunner.kt b/backend/app/src/main/kotlin/io/tolgee/postgresRunners/PostgresDockerRunner.kt index 9dbeb92cc1..8152e3db61 100644 --- a/backend/app/src/main/kotlin/io/tolgee/postgresRunners/PostgresDockerRunner.kt +++ b/backend/app/src/main/kotlin/io/tolgee/postgresRunners/PostgresDockerRunner.kt @@ -41,7 +41,8 @@ class PostgresDockerRunner( } override val datasourceUrl by lazy { - "jdbc:postgresql://localhost:${postgresAutostartProperties.port}/${postgresAutostartProperties.databaseName}?reWriteBatchedInserts=true" + "jdbc:postgresql://localhost:${postgresAutostartProperties.port}/${postgresAutostartProperties.databaseName}" + + "?reWriteBatchedInserts=true" } @PreDestroy diff --git a/backend/data/src/main/kotlin/io/tolgee/batch/ProgressManager.kt b/backend/data/src/main/kotlin/io/tolgee/batch/ProgressManager.kt index f97bd50c87..1ac65e1b3f 100644 --- a/backend/data/src/main/kotlin/io/tolgee/batch/ProgressManager.kt +++ b/backend/data/src/main/kotlin/io/tolgee/batch/ProgressManager.kt @@ -1,7 +1,11 @@ package io.tolgee.batch import io.tolgee.batch.data.BatchJobDto -import io.tolgee.batch.events.* +import io.tolgee.batch.events.OnBatchJobCancelled +import io.tolgee.batch.events.OnBatchJobFailed +import io.tolgee.batch.events.OnBatchJobProgress +import io.tolgee.batch.events.OnBatchJobStarted +import io.tolgee.batch.events.OnBatchJobSucceeded import io.tolgee.batch.state.BatchJobStateProvider import io.tolgee.batch.state.ExecutionState import io.tolgee.constants.Message diff --git a/backend/data/src/main/kotlin/io/tolgee/model/Notification.kt b/backend/data/src/main/kotlin/io/tolgee/model/Notification.kt index 096145acb3..4822a1297f 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/Notification.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/Notification.kt @@ -38,19 +38,23 @@ class Notification private constructor( @Enumerated(EnumType.STRING) val type: NotificationType, - @ManyToOne(fetch = FetchType.LAZY, cascade = [ CascadeType.REMOVE ]) // This data is very likely to be useless: lazy + // This data is very likely to be useless: lazy + @ManyToOne(fetch = FetchType.LAZY, cascade = [ CascadeType.REMOVE ]) @JoinColumn(nullable = false) val recipient: UserAccount, - @ManyToOne(fetch = FetchType.EAGER, cascade = [ CascadeType.REMOVE ]) // We most definitely need this to show the notification: eager + // We most definitely need this to show the notification: eager + @ManyToOne(fetch = FetchType.EAGER, cascade = [ CascadeType.REMOVE ]) @JoinColumn(nullable = false) val project: Project, - @ManyToMany(fetch = FetchType.EAGER, cascade = [ CascadeType.REMOVE ]) // We most definitely need this to show the notification: eager + // We most definitely need this to show the notification: eager + @ManyToMany(fetch = FetchType.EAGER, cascade = [ CascadeType.REMOVE ]) @JoinTable(name = "notification_activity_revisions") val activityRevisions: MutableList? = null, - @ManyToOne(fetch = FetchType.EAGER, cascade = [ CascadeType.REMOVE ]) // We most definitely need this to show the notification: eager + // We most definitely need this to show the notification: eager + @ManyToOne(fetch = FetchType.EAGER, cascade = [ CascadeType.REMOVE ]) val batchJob: BatchJob? = null, @Type(type = "jsonb") diff --git a/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionDataView.kt b/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionDataView.kt index fce02785b0..d063c760a3 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionDataView.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionDataView.kt @@ -30,6 +30,6 @@ class UserAccountProjectPermissionDataView( permissionsGranular: Array>?, ) { // I hate Hibernate - it *requires* an Array> or complains... - val basePermissionsGranular: List? = basePermissionsGranular?.map { enumValueOf(it.name) } - val permissionsGranular: List? = permissionsGranular?.map { enumValueOf(it.name) } + val basePermissionsGranular: List? = basePermissionsGranular?.map { enumValueOf(it.name) } + val permissionsGranular: List? = permissionsGranular?.map { enumValueOf(it.name) } } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationService.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationService.kt index 93783702b8..885d8ba8d4 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationService.kt @@ -101,7 +101,7 @@ class NotificationService( } companion object { - val debouncedNotificationTypes: EnumSet - = EnumSet.of(Notification.NotificationType.ACTIVITY) + val debouncedNotificationTypes: EnumSet = + EnumSet.of(Notification.NotificationType.ACTIVITY) } } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt index 57d4ea4395..17387d4a76 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt @@ -16,26 +16,20 @@ package io.tolgee.notifications.dispatchers -import io.tolgee.activity.ModifiedEntitiesType import io.tolgee.activity.data.ActivityType -import io.tolgee.events.OnProjectActivityEvent -import io.tolgee.model.Project import io.tolgee.model.activity.ActivityRevision import io.tolgee.model.batch.BatchJobStatus import io.tolgee.model.enums.Scope import io.tolgee.model.translation.Translation import io.tolgee.notifications.NotificationService -import io.tolgee.notifications.dto.NotificationCreateDto import io.tolgee.notifications.events.NotificationCreateEvent import io.tolgee.service.LanguageService import io.tolgee.service.security.PermissionService import io.tolgee.service.security.UserAccountService import io.tolgee.util.Logging import io.tolgee.util.logger -import org.springframework.context.ApplicationEventPublisher import org.springframework.context.event.EventListener import org.springframework.stereotype.Component -import javax.persistence.EntityManager @Component class UserNotificationDispatch( diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt index a988d97d62..80323ac839 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt @@ -29,10 +29,10 @@ data class NotificationCreateDto( ) { val meta: MutableMap = mutableMapOf() - constructor(project: Project, activityRevision: ActivityRevision): + constructor(project: Project, activityRevision: ActivityRevision) : this(project, activityRevision = activityRevision, batchJob = null) - constructor(project: Project, batchJob: BatchJob): + constructor(project: Project, batchJob: BatchJob) : this(project, activityRevision = null, batchJob = batchJob) init { diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt index c099547b02..796e912a9c 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt @@ -19,7 +19,6 @@ package io.tolgee.notifications.listeners import io.tolgee.batch.BatchJobService import io.tolgee.batch.data.BatchJobDto import io.tolgee.batch.events.* -import io.tolgee.model.Project import io.tolgee.model.batch.BatchJob import io.tolgee.model.batch.BatchJobStatus import io.tolgee.notifications.dto.NotificationCreateDto diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt index c9b794d942..587274ff0d 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt @@ -195,4 +195,3 @@ interface UserAccountRepository : JpaRepository { languageIds: List? ): List } - From fcecce7c5a6827c4441e2c830336afa1046c9e5a Mon Sep 17 00:00:00 2001 From: Cynthia Date: Mon, 20 Nov 2023 15:09:55 +0100 Subject: [PATCH 05/44] feat: finish user notification dispatch logic --- .../postgres/CustomPostgreSQLDialect.kt | 3 + .../kotlin/io/tolgee/model/Notification.kt | 63 +++---- .../main/kotlin/io/tolgee/model/Project.kt | 4 +- .../kotlin/io/tolgee/model/UserAccount.kt | 3 + .../UserAccountProjectPermissionDataView.kt | 8 + .../notifications/NotificationService.kt | 55 +++--- .../dispatchers/UserNotificationDispatch.kt | 168 +++++++++++++----- .../dto/NotificationCreateDto.kt | 60 +++++-- .../dto/NotificationDispatchParamsDto.kt | 26 +++ .../events/NotificationCreateEvent.kt | 2 + .../listeners/ActivityEventListener.kt | 11 +- .../listeners/BatchJobListener.kt | 36 ++-- .../tolgee/repository/LanguageRepository.kt | 4 +- .../repository/NotificationsRepository.kt | 19 +- .../repository/UserAccountRepository.kt | 19 +- .../io/tolgee/service/LanguageService.kt | 8 +- .../service/security/UserAccountService.kt | 9 +- .../main/resources/db/changelog/schema.xml | 53 ++++-- 18 files changed, 363 insertions(+), 188 deletions(-) create mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationDispatchParamsDto.kt diff --git a/backend/data/src/main/kotlin/io/tolgee/dialects/postgres/CustomPostgreSQLDialect.kt b/backend/data/src/main/kotlin/io/tolgee/dialects/postgres/CustomPostgreSQLDialect.kt index 1393577a87..f850fc6275 100644 --- a/backend/data/src/main/kotlin/io/tolgee/dialects/postgres/CustomPostgreSQLDialect.kt +++ b/backend/data/src/main/kotlin/io/tolgee/dialects/postgres/CustomPostgreSQLDialect.kt @@ -5,9 +5,11 @@ import com.vladmihalcea.hibernate.type.json.JsonBinaryType import org.hibernate.NullPrecedence import org.hibernate.dialect.PostgreSQL10Dialect import org.hibernate.dialect.function.SQLFunction +import org.hibernate.dialect.function.StandardSQLFunction import org.hibernate.engine.spi.Mapping import org.hibernate.engine.spi.SessionFactoryImplementor import org.hibernate.type.FloatType +import org.hibernate.type.StandardBasicTypes import org.hibernate.type.Type import java.sql.Types @@ -15,6 +17,7 @@ import java.sql.Types class CustomPostgreSQLDialect : PostgreSQL10Dialect() { init { registerHibernateType(Types.ARRAY, StringArrayType::class.java.name) + registerFunction("array_to_string", StandardSQLFunction("array_to_string", StandardBasicTypes.STRING)) } override fun renderOrderByElement( diff --git a/backend/data/src/main/kotlin/io/tolgee/model/Notification.kt b/backend/data/src/main/kotlin/io/tolgee/model/Notification.kt index 4822a1297f..4652800609 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/Notification.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/Notification.kt @@ -17,6 +17,7 @@ package io.tolgee.model import com.vladmihalcea.hibernate.type.json.JsonBinaryType +import io.tolgee.model.activity.ActivityModifiedEntity import io.tolgee.model.activity.ActivityRevision import io.tolgee.model.batch.BatchJob import org.hibernate.annotations.ColumnDefault @@ -25,7 +26,22 @@ import org.hibernate.annotations.TypeDef import org.hibernate.annotations.TypeDefs import org.hibernate.annotations.UpdateTimestamp import java.util.* -import javax.persistence.* +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.EnumType +import javax.persistence.Enumerated +import javax.persistence.FetchType +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.JoinColumn +import javax.persistence.JoinTable +import javax.persistence.ManyToMany +import javax.persistence.ManyToOne +import javax.persistence.OrderBy +import javax.persistence.SequenceGenerator +import javax.persistence.Temporal +import javax.persistence.TemporalType @Entity @TypeDefs( @@ -33,28 +49,33 @@ import javax.persistence.* TypeDef(name = "jsonb", typeClass = JsonBinaryType::class) ] ) -class Notification private constructor( +class Notification( @Column(nullable = false) @Enumerated(EnumType.STRING) val type: NotificationType, // This data is very likely to be useless: lazy - @ManyToOne(fetch = FetchType.LAZY, cascade = [ CascadeType.REMOVE ]) + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(nullable = false) val recipient: UserAccount, // We most definitely need this to show the notification: eager - @ManyToOne(fetch = FetchType.EAGER, cascade = [ CascadeType.REMOVE ]) + @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(nullable = false) val project: Project, // We most definitely need this to show the notification: eager - @ManyToMany(fetch = FetchType.EAGER, cascade = [ CascadeType.REMOVE ]) + @ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "notification_activity_revisions") - val activityRevisions: MutableList? = null, + val activityRevisions: MutableSet = mutableSetOf(), // We most definitely need this to show the notification: eager - @ManyToOne(fetch = FetchType.EAGER, cascade = [ CascadeType.REMOVE ]) + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable(name = "notification_activity_modified_entities") + val activityModifiedEntities: MutableSet = mutableSetOf(), + + // We most definitely need this to show the notification: eager + @ManyToOne(fetch = FetchType.EAGER) val batchJob: BatchJob? = null, @Type(type = "jsonb") @@ -77,34 +98,6 @@ class Notification private constructor( @Temporal(TemporalType.TIMESTAMP) val lastUpdated: Date = Date() - constructor( - recipient: UserAccount, - project: Project, - activityRevision: ActivityRevision, - meta: Map? = null, - ) : - this( - NotificationType.ACTIVITY, - recipient, - project, - activityRevisions = mutableListOf(activityRevision), - meta = meta?.toMutableMap() ?: mutableMapOf(), - ) - - constructor( - recipient: UserAccount, - project: Project, - batchJob: BatchJob, - meta: Map? = null, - ) : - this( - NotificationType.BATCH_JOB_FAILURE, - recipient, - project, - batchJob = batchJob, - meta = meta?.toMutableMap() ?: mutableMapOf(), - ) - enum class NotificationType { ACTIVITY, BATCH_JOB_FAILURE, diff --git a/backend/data/src/main/kotlin/io/tolgee/model/Project.kt b/backend/data/src/main/kotlin/io/tolgee/model/Project.kt index a21d1b6eb3..89472b77b6 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/Project.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/Project.kt @@ -63,7 +63,6 @@ class Project( @OneToMany(fetch = FetchType.LAZY, mappedBy = "project") var apiKeys: MutableSet = LinkedHashSet() - @Suppress("SetterBackingFieldAssignment") @ManyToOne(optional = true, fetch = FetchType.LAZY) @Deprecated(message = "Project can be owned only by organization") var userOwner: UserAccount? = null @@ -84,6 +83,9 @@ class Project( @OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, mappedBy = "project") var namespaces: MutableList = mutableListOf() + @OneToMany(fetch = FetchType.LAZY, cascade = [CascadeType.REMOVE], mappedBy = "project") + var notifications: MutableList = mutableListOf() + @ActivityLoggedProp override var avatarHash: String? = null diff --git a/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt b/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt index 85dcf21cdb..6bc8c0df6c 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt @@ -94,6 +94,9 @@ data class UserAccount( @ColumnDefault("true") var passwordChanged: Boolean = true + @OneToMany(fetch = FetchType.LAZY, cascade = [CascadeType.REMOVE], mappedBy = "recipient") + var notifications: MutableList = mutableListOf() + val isDeletable: Boolean get() = this.accountType != AccountType.MANAGED && !this.isInitialUser diff --git a/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionDataView.kt b/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionDataView.kt index d063c760a3..798980fb49 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionDataView.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionDataView.kt @@ -28,8 +28,16 @@ class UserAccountProjectPermissionDataView( basePermissionsGranular: Array>?, val permissionsBasic: ProjectPermissionType?, permissionsGranular: Array>?, + viewLanguageIdsConcatenated: String, ) { // I hate Hibernate - it *requires* an Array> or complains... val basePermissionsGranular: List? = basePermissionsGranular?.map { enumValueOf(it.name) } val permissionsGranular: List? = permissionsGranular?.map { enumValueOf(it.name) } + + // And don't get me started on its array support ^^ + val permittedViewLanguages = viewLanguageIdsConcatenated + .split(',') + .filter { it.isNotEmpty() } + .map { it.toLong() } + .ifEmpty { null } } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationService.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationService.kt index 885d8ba8d4..08ef06bd89 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationService.kt @@ -19,6 +19,7 @@ package io.tolgee.notifications import io.tolgee.model.Notification import io.tolgee.model.UserAccount import io.tolgee.notifications.dto.NotificationCreateDto +import io.tolgee.notifications.dto.NotificationDispatchParamsDto import io.tolgee.notifications.events.NotificationUserPushEvent import io.tolgee.repository.NotificationsRepository import org.springframework.context.ApplicationEventPublisher @@ -26,44 +27,48 @@ import org.springframework.data.domain.Pageable import org.springframework.scheduling.annotation.Async import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional -import java.util.EnumSet -import javax.persistence.EntityManager +import java.util.* @Service class NotificationService( private val notificationsRepository: NotificationsRepository, private val applicationEventPublisher: ApplicationEventPublisher, - private val entityManager: EntityManager, ) { @Async @Transactional - fun dispatchNotificationToUserId(notificationDto: NotificationCreateDto, user: Long) { - val userReference = entityManager.getReference(UserAccount::class.java, user) - return dispatchNotificationToUser(notificationDto, userReference) + fun dispatchNotification(notificationDto: NotificationCreateDto, params: NotificationDispatchParamsDto) { + return dispatchNotifications(notificationDto, listOf(params)) } @Async @Transactional - fun dispatchNotificationToUserIds(notificationDto: NotificationCreateDto, users: List) { - val usersReferences = users.map { entityManager.getReference(UserAccount::class.java, it) } - dispatchNotificationToUsers(notificationDto, usersReferences) - } - - @Async - @Transactional - fun dispatchNotificationToUser(notificationDto: NotificationCreateDto, user: UserAccount) = - dispatchNotificationToUsers(notificationDto, listOf(user)) - - @Async - @Transactional - fun dispatchNotificationToUsers(notificationDto: NotificationCreateDto, users: List) { + fun dispatchNotifications(notificationDto: NotificationCreateDto, params: List) { val notificationObjects = mutableSetOf() - - users.forEach { - val notification = notificationDto.toNotificationEntity(it) - notificationObjects.add( - notificationsRepository.save(notification) - ) + val users = params.map { it.recipient } + + val existingNotifications = + if (debouncedNotificationTypes.contains(notificationDto.type)) + notificationsRepository.findNotificationsToDebounceMappedByUser( + notificationDto.type, + notificationDto.project, + users, + ) + else emptyMap() + + params.forEach { + if (existingNotifications.containsKey(it.recipient.id)) { + val notification = existingNotifications[it.recipient.id]!! + notificationDto.mergeIntoNotificationEntity(notification, it) + + notificationObjects.add( + notificationsRepository.save(notification) + ) + } else { + val notification = notificationDto.toNotificationEntity(it) + notificationObjects.add( + notificationsRepository.save(notification) + ) + } } // Dispatch event diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt index 17387d4a76..c5fba2b8c4 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt @@ -17,11 +17,13 @@ package io.tolgee.notifications.dispatchers import io.tolgee.activity.data.ActivityType -import io.tolgee.model.activity.ActivityRevision +import io.tolgee.model.UserAccount import io.tolgee.model.batch.BatchJobStatus import io.tolgee.model.enums.Scope +import io.tolgee.model.key.Key import io.tolgee.model.translation.Translation import io.tolgee.notifications.NotificationService +import io.tolgee.notifications.dto.NotificationDispatchParamsDto import io.tolgee.notifications.events.NotificationCreateEvent import io.tolgee.service.LanguageService import io.tolgee.service.security.PermissionService @@ -30,6 +32,7 @@ import io.tolgee.util.Logging import io.tolgee.util.logger import org.springframework.context.event.EventListener import org.springframework.stereotype.Component +import javax.persistence.EntityManager @Component class UserNotificationDispatch( @@ -37,6 +40,7 @@ class UserNotificationDispatch( private val permissionService: PermissionService, private val languageService: LanguageService, private val notificationService: NotificationService, + private val entityManager: EntityManager, ) : Logging { @EventListener fun onNotificationCreate(e: NotificationCreateEvent) { @@ -50,24 +54,7 @@ class UserNotificationDispatch( } private fun handleActivityNotification(e: NotificationCreateEvent) { - val revision = e.notification.activityRevision!! - val users = getUsersConcernedByRevision(revision) - if (users.isEmpty()) return - - notificationService.dispatchNotificationToUserIds(e.notification, users) - } - - private fun handleBatchJobNotification(e: NotificationCreateEvent) { - // Only send a full notification for job failures. The rest will be ephemeral WebSocket based. - if (e.notification.meta["status"] != BatchJobStatus.FAILED) return - - val batchJob = e.notification.batchJob!! - val author = batchJob.author ?: return - notificationService.dispatchNotificationToUser(e.notification, author) - } - - private fun getUsersConcernedByRevision(revision: ActivityRevision): List { - return when (revision.type) { + when (e.notification.activityRevision!!.type) { ActivityType.CREATE_LANGUAGE, ActivityType.KEY_TAGS_EDIT, ActivityType.KEY_NAME_EDIT, @@ -75,8 +62,12 @@ class UserNotificationDispatch( ActivityType.NAMESPACE_EDIT, ActivityType.BATCH_TAG_KEYS, ActivityType.BATCH_UNTAG_KEYS, - ActivityType.BATCH_SET_KEYS_NAMESPACE - -> getAllUsersOfProject(revision) + ActivityType.BATCH_SET_KEYS_NAMESPACE, + ActivityType.COMPLEX_EDIT -> + handleGenericActivityNotification(e) + + ActivityType.SCREENSHOT_ADD -> + handleScreenshotActivityNotification(e) ActivityType.SET_TRANSLATION_STATE, ActivityType.SET_TRANSLATIONS, @@ -90,16 +81,14 @@ class UserNotificationDispatch( ActivityType.AUTO_TRANSLATE, ActivityType.BATCH_CLEAR_TRANSLATIONS, ActivityType.BATCH_COPY_TRANSLATIONS, - ActivityType.BATCH_SET_TRANSLATION_STATE - -> getUsersConcernedByTranslationChange(revision) - - ActivityType.SCREENSHOT_ADD - -> getUsersConcernedByScreenshotChange(revision) + ActivityType.BATCH_SET_TRANSLATION_STATE -> + handleTranslationActivityNotification(e) - ActivityType.IMPORT -> TODO() - ActivityType.COMPLEX_EDIT -> TODO() + ActivityType.IMPORT -> + handleImportActivityNotification(e) // Do not show a notification about those type of events + // Intentionally not done as an else block to make this not compile if new activities are added ActivityType.EDIT_PROJECT, ActivityType.EDIT_LANGUAGE, ActivityType.DELETE_LANGUAGE, @@ -108,40 +97,129 @@ class UserNotificationDispatch( ActivityType.SCREENSHOT_DELETE, ActivityType.CREATE_PROJECT, ActivityType.UNKNOWN, - null -> emptyList() + null -> {} } } - private fun getAllUsersOfProject(activityRevision: ActivityRevision): List { - return userAccountService.getAllPermissionInformationOfPermittedUsersInProject(activityRevision.projectId!!) - .map { it.id } + private fun handleBatchJobNotification(e: NotificationCreateEvent) { + // Only send a full notification for job failures. The rest will be ephemeral WebSocket based. + if (e.notification.meta["status"] != BatchJobStatus.FAILED) return + + val batchJob = e.notification.batchJob!! + val author = batchJob.author ?: return + notificationService.dispatchNotification( + e.notification, + NotificationDispatchParamsDto(author) + ) } - private fun getUsersConcernedByScreenshotChange(activityRevision: ActivityRevision): List { - return userAccountService.getAllPermissionInformationOfPermittedUsersInProject(activityRevision.projectId!!) + private fun handleGenericActivityNotification(e: NotificationCreateEvent) { + val revision = e.notification.activityRevision!! + val users = userAccountService.getAllPermissionInformationOfPermittedUsersInProject(revision.projectId!!) + + val dispatches = users + .filter { it.id != e.responsibleUser?.id } + .map { + NotificationDispatchParamsDto( + recipient = entityManager.getReference(UserAccount::class.java, it.id), + activityModifiedEntities = revision.modifiedEntities, + ) + } + + notificationService.dispatchNotifications(e.notification, dispatches) + } + + private fun handleScreenshotActivityNotification(e: NotificationCreateEvent) { + val revision = e.notification.activityRevision!! + val users = userAccountService.getAllPermissionInformationOfPermittedUsersInProject(revision.projectId!!) + + val dispatches = users .filter { + if (it.id == e.responsibleUser?.id) return@filter false val computedPermissions = permissionService.computeProjectPermission(it) computedPermissions.expandedScopes.contains(Scope.SCREENSHOTS_VIEW) } - .map { it.id } + .map { + NotificationDispatchParamsDto( + recipient = entityManager.getReference(UserAccount::class.java, it.id), + activityModifiedEntities = revision.modifiedEntities, + ) + } + + notificationService.dispatchNotifications(e.notification, dispatches) } - private fun getUsersConcernedByTranslationChange(activityRevision: ActivityRevision): List { - val translationIds = activityRevision.modifiedEntities + private fun handleTranslationActivityNotification(e: NotificationCreateEvent) { + val revision = e.notification.activityRevision!! + val users = userAccountService.getAllPermissionInformationOfPermittedUsersInProject(revision.projectId!!) + + val translationEntities = revision.modifiedEntities + .filter { it.entityClass == Translation::class.simpleName } + + val translationIds = translationEntities.map { it.entityId } + val translationToLangMap = languageService.findLanguageIdsOfTranslations(translationIds) + + val dispatches = users + .filter { + if (it.id == e.responsibleUser?.id) return@filter false + val computedPermissions = permissionService.computeProjectPermission(it) + computedPermissions.expandedScopes.contains(Scope.TRANSLATIONS_VIEW) + } + .map { + val visibleModifiedEntities = translationEntities.filter { entity -> + val languageId = translationToLangMap[entity.entityId] ?: return@filter false + it.permittedViewLanguages?.contains(languageId) != false + } + + NotificationDispatchParamsDto( + recipient = entityManager.getReference(UserAccount::class.java, it.id), + activityModifiedEntities = visibleModifiedEntities, + ) + } + + notificationService.dispatchNotifications(e.notification, dispatches) + } + + private fun handleImportActivityNotification(e: NotificationCreateEvent) { + val revision = e.notification.activityRevision!! + + val keysCount = revision.modifiedEntities.count { it.entityClass == Key::class.simpleName } + + // Count translations per locale + val translationIds = revision.modifiedEntities .filter { it.entityClass == Translation::class.simpleName } .map { it.entityId } - val langIds = languageService.findLanguageIdsOfTranslations(translationIds) - return userAccountService.getAllPermissionInformationOfPermittedUsersInProject( - activityRevision.projectId!!, - langIds - ) + val translationToLangMap = languageService.findLanguageIdsOfTranslations(translationIds) + + val importedTranslationsPerLocale = mutableMapOf() + translationToLangMap.values.forEach { + importedTranslationsPerLocale.merge(it, 1) { a, b -> a + b } + } + + // Filter users + val users = userAccountService.getAllPermissionInformationOfPermittedUsersInProject(revision.projectId!!) + + val dispatches = users .filter { + if (it.id == e.responsibleUser?.id) return@filter false val computedPermissions = permissionService.computeProjectPermission(it) - println("--") - println(computedPermissions.expandedScopes.joinToString(", ")) computedPermissions.expandedScopes.contains(Scope.TRANSLATIONS_VIEW) } - .map { it.id } + .map { + val userVisibleTranslationCount = importedTranslationsPerLocale + .filterKeys { l -> it.permittedViewLanguages?.contains(l) != false } + .values.reduce { acc, i -> acc + i } + + NotificationDispatchParamsDto( + recipient = entityManager.getReference(UserAccount::class.java, it.id), + meta = mutableMapOf("keysCount" to keysCount, "translationsCount" to userVisibleTranslationCount) + ) + } + .filter { + it.meta["translationsCount"] != 0 + } + + notificationService.dispatchNotifications(e.notification, dispatches) } } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt index 80323ac839..45ec691fe8 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt @@ -18,7 +18,6 @@ package io.tolgee.notifications.dto import io.tolgee.model.Notification import io.tolgee.model.Project -import io.tolgee.model.UserAccount import io.tolgee.model.activity.ActivityRevision import io.tolgee.model.batch.BatchJob @@ -26,8 +25,13 @@ data class NotificationCreateDto( val project: Project, val activityRevision: ActivityRevision? = null, val batchJob: BatchJob? = null, + val meta: MutableMap = mutableMapOf(), ) { - val meta: MutableMap = mutableMapOf() + val type = when { + activityRevision != null -> Notification.NotificationType.ACTIVITY + batchJob != null -> Notification.NotificationType.BATCH_JOB_FAILURE + else -> throw IllegalStateException("No entity attached to this DTO!") + } constructor(project: Project, activityRevision: ActivityRevision) : this(project, activityRevision = activityRevision, batchJob = null) @@ -45,14 +49,50 @@ data class NotificationCreateDto( } } - fun toNotificationEntity(user: UserAccount): Notification { - return when { - activityRevision != null -> - Notification(user, project, activityRevision, meta) - batchJob != null -> - Notification(user, project, batchJob, meta) - else -> - throw IllegalStateException("No entity attached to this DTO??") + fun toNotificationEntity(params: NotificationDispatchParamsDto): Notification { + val mergedMeta = meta.toMutableMap() + mergedMeta.putAll(params.meta) + + return Notification( + type = type, + recipient = params.recipient, + project = project, + activityRevisions = activityRevision?.let { mutableSetOf(activityRevision) } ?: mutableSetOf(), + activityModifiedEntities = params.activityModifiedEntities.toMutableSet(), + meta = mergedMeta, + ) + } + + fun mergeIntoNotificationEntity(notification: Notification, params: NotificationDispatchParamsDto) { + when (notification.type) { + Notification.NotificationType.ACTIVITY -> + mergeIntoNotificationEntityActivity(notification, params) + + Notification.NotificationType.BATCH_JOB_FAILURE -> + throw IllegalArgumentException("Cannot merge notifications of type ${notification.type}") } } + + private fun mergeIntoNotificationEntityActivity(notification: Notification, params: NotificationDispatchParamsDto) { + if (activityRevision == null) + throw IllegalArgumentException("Tried to merge notifications of incompatible type") + if (notification.recipient.id != params.recipient.id) + throw IllegalArgumentException("Tried to merge a notification for user#${notification.recipient.id}, " + + "but specified ${params.recipient.id} as recipient in notification dispatch parameters") + + notification.activityRevisions.add(activityRevision) + params.activityModifiedEntities.forEach { + val existing = notification.activityModifiedEntities.find { ex -> + ex.activityRevision.id == it.activityRevision.id && + ex.entityId == it.entityId && + ex.entityClass == it.entityClass + } + + if (existing == null) { + notification.activityModifiedEntities.add(it) + } + } + + notification.meta.putAll(params.meta) + } } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationDispatchParamsDto.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationDispatchParamsDto.kt new file mode 100644 index 0000000000..faebba87cb --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationDispatchParamsDto.kt @@ -0,0 +1,26 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.notifications.dto + +import io.tolgee.model.UserAccount +import io.tolgee.model.activity.ActivityModifiedEntity + +data class NotificationDispatchParamsDto( + val recipient: UserAccount, + val activityModifiedEntities: List = emptyList(), + val meta: MutableMap = mutableMapOf(), +) diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationCreateEvent.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationCreateEvent.kt index 968bf0e2fb..c7fa2a7363 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationCreateEvent.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationCreateEvent.kt @@ -16,9 +16,11 @@ package io.tolgee.notifications.events +import io.tolgee.model.UserAccount import io.tolgee.notifications.dto.NotificationCreateDto data class NotificationCreateEvent( val notification: NotificationCreateDto, + val responsibleUser: UserAccount?, val source: Any? = null ) diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt index eb8833f5c2..5a43db091f 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt @@ -18,6 +18,7 @@ package io.tolgee.notifications.listeners import io.tolgee.events.OnProjectActivityStoredEvent import io.tolgee.model.Project +import io.tolgee.model.UserAccount import io.tolgee.notifications.dto.NotificationCreateDto import io.tolgee.notifications.events.NotificationCreateEvent import io.tolgee.util.Logging @@ -45,13 +46,21 @@ class ActivityEventListener( val projectId = e.activityRevision.projectId ?: return val project = entityManager.getReference(Project::class.java, projectId) + val responsibleUser = e.activityRevision.authorId?.let { + entityManager.getReference(UserAccount::class.java, it) + } + val notificationDto = NotificationCreateDto( project = project, activityRevision = e.activityRevision ) applicationEventPublisher.publishEvent( - NotificationCreateEvent(notificationDto, e) + NotificationCreateEvent( + notificationDto, + responsibleUser, + source = e, + ) ) } } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt index 796e912a9c..a33a730c0f 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt @@ -28,12 +28,10 @@ import io.tolgee.util.logger import org.springframework.context.ApplicationEventPublisher import org.springframework.context.event.EventListener import org.springframework.stereotype.Component -import javax.persistence.EntityManager @Component class BatchJobListener( private val applicationEventPublisher: ApplicationEventPublisher, - private val entityManager: EntityManager, private val batchJobService: BatchJobService, ) : Logging { @EventListener @@ -46,10 +44,7 @@ class BatchJobListener( val notification = createNotificationBase(e.job) notification.meta["status"] = BatchJobStatus.PENDING - - applicationEventPublisher.publishEvent( - NotificationCreateEvent(notification, e) - ) + doDispatch(notification, e) } @EventListener @@ -64,10 +59,7 @@ class BatchJobListener( notification.meta["status"] = BatchJobStatus.RUNNING notification.meta["processed"] = 0 notification.meta["total"] = e.job.totalChunks - - applicationEventPublisher.publishEvent( - NotificationCreateEvent(notification, e) - ) + doDispatch(notification, e) } @EventListener @@ -84,10 +76,7 @@ class BatchJobListener( notification.meta["status"] = BatchJobStatus.RUNNING notification.meta["processed"] = e.processed notification.meta["total"] = e.total - - applicationEventPublisher.publishEvent( - NotificationCreateEvent(notification, e) - ) + doDispatch(notification, e) } @EventListener @@ -100,10 +89,7 @@ class BatchJobListener( val notification = createNotificationBase(e.job) notification.meta["status"] = BatchJobStatus.SUCCESS - - applicationEventPublisher.publishEvent( - NotificationCreateEvent(notification, e) - ) + doDispatch(notification, e) } @EventListener @@ -116,10 +102,7 @@ class BatchJobListener( val notification = createNotificationBase(e.job) notification.meta["status"] = BatchJobStatus.CANCELLED - - applicationEventPublisher.publishEvent( - NotificationCreateEvent(notification, e) - ) + doDispatch(notification, e) } @EventListener @@ -132,9 +115,16 @@ class BatchJobListener( val notification = createNotificationBase(e.job) notification.meta["status"] = BatchJobStatus.FAILED + doDispatch(notification, e) + } + private fun doDispatch(notification: NotificationCreateDto, source: Any) { applicationEventPublisher.publishEvent( - NotificationCreateEvent(notification, e) + NotificationCreateEvent( + notification, + source = source, + responsibleUser = null, + ) ) } diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt index e371c312ae..9a270e2bea 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt @@ -22,10 +22,10 @@ interface LanguageRepository : JpaRepository { @Query( """ - SELECT t.language.id + SELECT new map(t.id, t.language.id) FROM Translation t WHERE t.id IN :translationIds """ ) - fun findLanguageIdsOfTranslations(translationIds: List): List + fun findLanguageIdsOfTranslations(translationIds: List): Map } diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/NotificationsRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/NotificationsRepository.kt index e7f58963b5..938f197063 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/NotificationsRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/NotificationsRepository.kt @@ -31,13 +31,24 @@ interface NotificationsRepository : JpaRepository { fun findAllByMarkedDoneAtNotNullAndRecipient(recipient: UserAccount, pageable: Pageable): List - fun findAllByUnreadTrueAndTypeAndProjectAndRecipientIn( + fun countNotificationsByRecipientAndUnreadTrue(recipient: UserAccount): Int + + @Query( + """ + SELECT new map(n.recipient.id, n) + FROM Notification n + WHERE + n.unread = true AND + n.type = :type AND + n.project = :project AND + n.recipient IN :recipients + """ + ) + fun findNotificationsToDebounceMappedByUser( type: Notification.NotificationType, project: Project, recipients: Collection, - ): List - - fun countNotificationsByRecipientAndUnreadTrue(recipient: UserAccount): Int + ): Map @Modifying @Query("UPDATE Notification n SET n.unread = false WHERE n.recipient = ?1 AND n.id IN ?2") diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt index 587274ff0d..2da39c4572 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt @@ -157,14 +157,15 @@ interface UserAccountRepository : JpaRepository { @Query( """ - SELECT DISTINCT new io.tolgee.model.views.UserAccountProjectPermissionDataView( + SELECT new io.tolgee.model.views.UserAccountProjectPermissionDataView( ua.id, p.id, org_r.type, perm_org.type, perm_org._scopes, perm.type, - perm._scopes + perm._scopes, + array_to_string(array_agg(l.id), ',') ) FROM UserAccount ua, Project p LEFT JOIN OrganizationRole org_r ON @@ -181,17 +182,11 @@ interface UserAccountRepository : JpaRepository { WHERE p.id = :projectId AND ua.deletedAt IS NULL AND ( - (perm._scopes IS NOT NULL AND perm._scopes != '{}') OR perm.type IS NOT NULL OR - (perm_org._scopes IS NOT NULL AND perm_org._scopes != '{}') OR perm_org.type IS NOT NULL - ) AND ( - (:languageIds) IS NULL OR - l.id IS NULL OR - l.id IN (:languageIds) + (perm._scopes IS NOT NULL AND perm._scopes != '{}') OR perm.type IS NOT NULL OR + (perm_org._scopes IS NOT NULL AND perm_org._scopes != '{}') OR perm_org.type IS NOT NULL ) + GROUP BY ua.id, p.id, org_r.type, perm_org.type, perm_org._scopes, perm.type, perm._scopes """ ) - fun findAllPermittedUsersProjectPermissionView( - projectId: Long, - languageIds: List? - ): List + fun findAllPermittedUsersProjectPermissionView(projectId: Long): List } diff --git a/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt b/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt index 77517a796b..e1f2f51822 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt @@ -8,7 +8,6 @@ import io.tolgee.model.Language.Companion.fromRequestDTO import io.tolgee.model.Project import io.tolgee.model.enums.Scope import io.tolgee.repository.LanguageRepository -import io.tolgee.service.machineTranslation.MtServiceConfigService import io.tolgee.service.project.ProjectService import io.tolgee.service.security.PermissionService import io.tolgee.service.security.SecurityService @@ -35,10 +34,6 @@ class LanguageService( @set:Lazy lateinit var translationService: TranslationService - @set:Autowired - @set:Lazy - lateinit var mtServiceConfigService: MtServiceConfigService - @Transactional fun createLanguage(dto: LanguageDto?, project: Project): Language { val language = fromRequestDTO(dto!!) @@ -163,10 +158,11 @@ class LanguageService( return languageRepository.findByNameAndProject(name, project) } - fun findLanguageIdsOfTranslations(translationIds: List): List { + fun findLanguageIdsOfTranslations(translationIds: List): Map { return languageRepository.findLanguageIdsOfTranslations(translationIds) } + @Transactional fun deleteAllByProject(projectId: Long) { findAll(projectId).forEach { deleteLanguage(it.id) diff --git a/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt b/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt index e28fadd53a..b6340d3464 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt @@ -302,15 +302,10 @@ class UserAccountService( } } - /** - * Returns a view of all users ids who are allowed to see at least one language of [languageIds] - * (or all permitted users if null) and their permissions. - */ fun getAllPermissionInformationOfPermittedUsersInProject( - projectId: Long, - languageIds: List? = null, + projectId: Long ): List { - return userAccountRepository.findAllPermittedUsersProjectPermissionView(projectId, languageIds) + return userAccountRepository.findAllPermittedUsersProjectPermissionView(projectId) } @Transactional diff --git a/backend/data/src/main/resources/db/changelog/schema.xml b/backend/data/src/main/resources/db/changelog/schema.xml index 6c4de7192b..7eb7728337 100644 --- a/backend/data/src/main/resources/db/changelog/schema.xml +++ b/backend/data/src/main/resources/db/changelog/schema.xml @@ -2760,18 +2760,21 @@ - + + + + - + - + - + @@ -2783,35 +2786,51 @@ - + + + + + + + + + + + + + + + + + - + - + - + - + + + + - + - + - + - - - - - + + From bd8bfabdce5c77b1fcb8db28e97c6365fbf28169 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Tue, 21 Nov 2023 12:04:29 +0100 Subject: [PATCH 06/44] fix: make fetching translation to language maps work again --- .../notifications/NotificationDispatchTest.kt | 110 ++++++++++++++++++ .../data/NotificationsTestData.kt | 8 +- .../dispatchers/UserNotificationDispatch.kt | 2 +- .../tolgee/repository/LanguageRepository.kt | 2 +- .../repository/NotificationsRepository.kt | 2 + .../io/tolgee/service/LanguageService.kt | 1 + .../main/resources/db/changelog/schema.xml | 2 +- 7 files changed, 120 insertions(+), 7 deletions(-) create mode 100644 backend/app/src/test/kotlin/io/tolgee/notifications/NotificationDispatchTest.kt diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/NotificationDispatchTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/NotificationDispatchTest.kt new file mode 100644 index 0000000000..b7915af516 --- /dev/null +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/NotificationDispatchTest.kt @@ -0,0 +1,110 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.notifications + +import io.tolgee.development.testDataBuilder.data.NotificationsTestData +import io.tolgee.dtos.request.key.CreateKeyDto +import io.tolgee.fixtures.andIsCreated +import io.tolgee.repository.NotificationsRepository +import io.tolgee.testing.AuthorizedControllerTest +import io.tolgee.testing.assert +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.mockito.Mockito +import org.mockito.kotlin.any +import org.mockito.kotlin.doAnswer +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.mock.mockito.SpyBean +import java.util.concurrent.Semaphore +import java.util.concurrent.TimeUnit + +class NotificationDispatchTest : AuthorizedControllerTest() { + lateinit var testData: NotificationsTestData + + @Autowired + lateinit var notificationService: NotificationService + + @SpyBean + @Autowired + lateinit var notificationsRepository: NotificationsRepository + + lateinit var semaphore: Semaphore + + @BeforeEach + fun setupEnvironment() { + testData = NotificationsTestData() + testDataService.saveTestData(testData.root) + + semaphore = Semaphore(0) + + doAnswer { + entityManager.persist(it.arguments[0]) + entityManager.flush() + + entityManager.refresh(it.arguments[0]) + semaphore.release() + it.arguments[0] + }.`when`(notificationsRepository).save(any()) + } + + @AfterEach + fun clearEnvironment() { + Mockito.reset(notificationsRepository) + } + + @Test + fun `it dispatches notifications to everyone in project`() { + performAuthPost( + "/v2/projects/${testData.project1.id}/keys/create", + CreateKeyDto(name = "test-key") + ).andIsCreated + + waitUntilNotificationDispatch(6) + val adminNotifications = notificationsRepository.findAllByRecipient(testData.admin) + val projectManagerNotifications = notificationsRepository.findAllByRecipient(testData.projectManager) + val frenchTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchTranslator) + val czechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.czechTranslator) + val germanTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.germanTranslator) + val frenchCzechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchCzechTranslator) + val bobNotifications = notificationsRepository.findAllByRecipient(testData.bob) + val aliceNotifications = notificationsRepository.findAllByRecipient(testData.alice) + + adminNotifications.assert.hasSize(0) + projectManagerNotifications.assert.hasSize(1) + frenchTranslatorNotifications.assert.hasSize(1) + czechTranslatorNotifications.assert.hasSize(1) + germanTranslatorNotifications.assert.hasSize(1) + frenchCzechTranslatorNotifications.assert.hasSize(1) + bobNotifications.assert.hasSize(1) + aliceNotifications.assert.hasSize(0) + } + + private fun waitUntilNotificationDispatch(count: Int = 1) { + val dispatched = semaphore.tryAcquire(count, 1L, TimeUnit.SECONDS) + dispatched.assert + .withFailMessage("Expected at least $count notification(s) to be dispatched.") + .isTrue() + } + + private fun ensureNoNotificationDispatch() { + val dispatched = semaphore.tryAcquire(1L, TimeUnit.SECONDS) + dispatched.assert + .withFailMessage("Expected no notifications to be dispatched.") + .isFalse() + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationsTestData.kt b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationsTestData.kt index 94f5395dad..b1cb8d36fe 100644 --- a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationsTestData.kt +++ b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationsTestData.kt @@ -206,7 +206,7 @@ class NotificationsTestData { addPermission { user = frenchTranslator - scopes = ProjectPermissionType.REVIEW.availableScopes + type = ProjectPermissionType.REVIEW viewLanguages.add(en.self) viewLanguages.add(fr.self) translateLanguages.add(en.self) @@ -217,7 +217,7 @@ class NotificationsTestData { addPermission { user = czechTranslator - scopes = ProjectPermissionType.REVIEW.availableScopes + type = ProjectPermissionType.REVIEW viewLanguages.add(en.self) viewLanguages.add(cz.self) translateLanguages.add(en.self) @@ -228,7 +228,7 @@ class NotificationsTestData { addPermission { user = germanTranslator - scopes = ProjectPermissionType.REVIEW.availableScopes + type = ProjectPermissionType.REVIEW viewLanguages.add(en.self) viewLanguages.add(de.self) translateLanguages.add(en.self) @@ -239,7 +239,7 @@ class NotificationsTestData { addPermission { user = frenchCzechTranslator - scopes = ProjectPermissionType.REVIEW.availableScopes + type = ProjectPermissionType.REVIEW viewLanguages.add(en.self) viewLanguages.add(fr.self) viewLanguages.add(cz.self) diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt index c5fba2b8c4..f8510ee2b0 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt @@ -102,7 +102,7 @@ class UserNotificationDispatch( } private fun handleBatchJobNotification(e: NotificationCreateEvent) { - // Only send a full notification for job failures. The rest will be ephemeral WebSocket based. + // Only send a full notification for job failures. if (e.notification.meta["status"] != BatchJobStatus.FAILED) return val batchJob = e.notification.batchJob!! diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt index 9a270e2bea..ed7c05ff6f 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt @@ -27,5 +27,5 @@ interface LanguageRepository : JpaRepository { WHERE t.id IN :translationIds """ ) - fun findLanguageIdsOfTranslations(translationIds: List): Map + fun findLanguageIdsOfTranslations(translationIds: List): List> } diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/NotificationsRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/NotificationsRepository.kt index 938f197063..fc730d332b 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/NotificationsRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/NotificationsRepository.kt @@ -27,6 +27,8 @@ import org.springframework.stereotype.Repository @Repository interface NotificationsRepository : JpaRepository { + fun findAllByRecipient(recipient: UserAccount): List + fun findAllByMarkedDoneAtNullAndRecipient(recipient: UserAccount, pageable: Pageable): List fun findAllByMarkedDoneAtNotNullAndRecipient(recipient: UserAccount, pageable: Pageable): List diff --git a/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt b/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt index e1f2f51822..6f39e7c156 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt @@ -160,6 +160,7 @@ class LanguageService( fun findLanguageIdsOfTranslations(translationIds: List): Map { return languageRepository.findLanguageIdsOfTranslations(translationIds) + .reduce { acc, map -> acc.plus(map) } } @Transactional diff --git a/backend/data/src/main/resources/db/changelog/schema.xml b/backend/data/src/main/resources/db/changelog/schema.xml index 7eb7728337..5d9bc7dc8c 100644 --- a/backend/data/src/main/resources/db/changelog/schema.xml +++ b/backend/data/src/main/resources/db/changelog/schema.xml @@ -2770,7 +2770,7 @@ - + From a850303d934af0be43ac850c67237f12fc8ddd3a Mon Sep 17 00:00:00 2001 From: Cynthia Date: Fri, 24 Nov 2023 18:32:37 +0100 Subject: [PATCH 07/44] tests: test notification dispatching --- .../notifications/AbstractNotificationTest.kt | 87 ++++++ .../notifications/NotificationDispatchTest.kt | 256 ++++++++++++++---- .../data/NotificationsTestData.kt | 12 +- .../notifications/NotificationService.kt | 3 - .../dispatchers/UserNotificationDispatch.kt | 5 + .../dto/NotificationCreateDto.kt | 6 +- .../tolgee/repository/LanguageRepository.kt | 4 +- .../io/tolgee/service/LanguageService.kt | 6 +- .../src/main/kotlin/io/tolgee/util/dateExt.kt | 6 + 9 files changed, 325 insertions(+), 60 deletions(-) create mode 100644 backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt new file mode 100644 index 0000000000..f06d1adfeb --- /dev/null +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt @@ -0,0 +1,87 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.notifications + +import io.tolgee.repository.NotificationsRepository +import io.tolgee.testing.AuthorizedControllerTest +import io.tolgee.testing.assert +import io.tolgee.util.addMilliseconds +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.mockito.Mockito +import org.mockito.kotlin.any +import org.mockito.kotlin.doAnswer +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.mock.mockito.SpyBean +import org.springframework.scheduling.TaskScheduler +import java.util.* +import java.util.concurrent.Semaphore +import java.util.concurrent.TimeUnit + +abstract class AbstractNotificationTest : AuthorizedControllerTest() { + @Autowired + lateinit var notificationService: NotificationService + + @Autowired + lateinit var taskScheduler: TaskScheduler + + @SpyBean + @Autowired + lateinit var notificationsRepository: NotificationsRepository + + lateinit var semaphore: Semaphore + + @BeforeEach + fun setupWatcher() { + semaphore = Semaphore(0) + + doAnswer { + entityManager.persist(it.arguments[0]) + entityManager.flush() + + entityManager.refresh(it.arguments[0]) + + // Wait a bit to make sure everything's *actually* persisted + // Kind of an ugly way to synchronize everything, but it is what it is + taskScheduler.schedule( + { semaphore.release() }, + Date().addMilliseconds(100) + ) + + it.arguments[0] + }.`when`(notificationsRepository).save(any()) + } + + @AfterEach + fun clearWatcher() { + Mockito.reset(notificationsRepository) + } + + fun waitUntilNotificationDispatch(count: Int = 1) { + val dispatched = semaphore.tryAcquire(count, 2L, TimeUnit.SECONDS) + dispatched.assert + .withFailMessage("Expected at least $count notification(s) to be dispatched.") + .isTrue() + } + + fun ensureNoNotificationDispatch() { + val dispatched = semaphore.tryAcquire(2L, TimeUnit.SECONDS) + dispatched.assert + .withFailMessage("Expected no notifications to be dispatched.") + .isFalse() + } +} diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/NotificationDispatchTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/NotificationDispatchTest.kt index b7915af516..b770e64aab 100644 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/NotificationDispatchTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/NotificationDispatchTest.kt @@ -18,57 +18,227 @@ package io.tolgee.notifications import io.tolgee.development.testDataBuilder.data.NotificationsTestData import io.tolgee.dtos.request.key.CreateKeyDto +import io.tolgee.dtos.request.translation.SetTranslationsWithKeyDto import io.tolgee.fixtures.andIsCreated -import io.tolgee.repository.NotificationsRepository -import io.tolgee.testing.AuthorizedControllerTest +import io.tolgee.fixtures.andIsOk import io.tolgee.testing.assert -import org.junit.jupiter.api.AfterEach +import io.tolgee.util.generateImage import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test -import org.mockito.Mockito -import org.mockito.kotlin.any -import org.mockito.kotlin.doAnswer -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.mock.mockito.SpyBean -import java.util.concurrent.Semaphore -import java.util.concurrent.TimeUnit - -class NotificationDispatchTest : AuthorizedControllerTest() { - lateinit var testData: NotificationsTestData - - @Autowired - lateinit var notificationService: NotificationService +import org.springframework.mock.web.MockMultipartFile - @SpyBean - @Autowired - lateinit var notificationsRepository: NotificationsRepository - - lateinit var semaphore: Semaphore +class NotificationDispatchTest : AbstractNotificationTest() { + lateinit var testData: NotificationsTestData @BeforeEach - fun setupEnvironment() { + fun createTestData() { testData = NotificationsTestData() testDataService.saveTestData(testData.root) + } - semaphore = Semaphore(0) + @Test + fun `it dispatches notifications to everyone in project`() { + performAuthPost( + "/v2/projects/${testData.project1.id}/keys/create", + CreateKeyDto(name = "test-key") + ).andIsCreated - doAnswer { - entityManager.persist(it.arguments[0]) - entityManager.flush() + waitUntilNotificationDispatch(7) + val adminNotifications = notificationsRepository.findAllByRecipient(testData.admin) + val acmeChiefNotifications = notificationsRepository.findAllByRecipient(testData.orgAdmin) + val projectManagerNotifications = notificationsRepository.findAllByRecipient(testData.projectManager) + val frenchTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchTranslator) + val czechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.czechTranslator) + val germanTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.germanTranslator) + val frenchCzechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchCzechTranslator) + val bobNotifications = notificationsRepository.findAllByRecipient(testData.bob) + val aliceNotifications = notificationsRepository.findAllByRecipient(testData.alice) + + adminNotifications.assert.hasSize(0) + acmeChiefNotifications.assert.hasSize(1) + projectManagerNotifications.assert.hasSize(1) + frenchTranslatorNotifications.assert.hasSize(1) + czechTranslatorNotifications.assert.hasSize(1) + germanTranslatorNotifications.assert.hasSize(1) + frenchCzechTranslatorNotifications.assert.hasSize(1) + bobNotifications.assert.hasSize(1) + aliceNotifications.assert.hasSize(0) - entityManager.refresh(it.arguments[0]) - semaphore.release() - it.arguments[0] - }.`when`(notificationsRepository).save(any()) + ensureNoNotificationDispatch() } - @AfterEach - fun clearEnvironment() { - Mockito.reset(notificationsRepository) + @Test + fun `it does not dispatch notifications to people without the permission to see the change`() { + performAuthMultipart( + url = "/v2/projects/${testData.project1.id}/keys/${testData.keyProject1.id}/screenshots", + files = listOf( + MockMultipartFile( + "screenshot", "originalShot.png", "image/png", + generateImage(100, 100).inputStream.readAllBytes() + ) + ) + ).andIsCreated + + waitUntilNotificationDispatch(6) + val acmeChiefNotifications = notificationsRepository.findAllByRecipient(testData.orgAdmin) + val projectManagerNotifications = notificationsRepository.findAllByRecipient(testData.projectManager) + val frenchTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchTranslator) + val czechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.czechTranslator) + val germanTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.germanTranslator) + val frenchCzechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchCzechTranslator) + val bobNotifications = notificationsRepository.findAllByRecipient(testData.bob) + + acmeChiefNotifications.assert.hasSize(1) + projectManagerNotifications.assert.hasSize(1) + frenchTranslatorNotifications.assert.hasSize(1) + czechTranslatorNotifications.assert.hasSize(1) + germanTranslatorNotifications.assert.hasSize(1) + frenchCzechTranslatorNotifications.assert.hasSize(1) + bobNotifications.assert.hasSize(0) + + ensureNoNotificationDispatch() } @Test - fun `it dispatches notifications to everyone in project`() { + fun `it does not dispatch notifications to people without the permission to see the target language`() { + performAuthPut( + url = "/v2/projects/${testData.project1.id}/translations", + content = SetTranslationsWithKeyDto( + key = testData.keyProject1.name, + translations = mapOf("fr" to "Superb French translation!") + ) + ).andIsOk + + waitUntilNotificationDispatch(5) + val acmeChiefNotifications = notificationsRepository.findAllByRecipient(testData.orgAdmin) + val projectManagerNotifications = notificationsRepository.findAllByRecipient(testData.projectManager) + val frenchTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchTranslator) + val czechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.czechTranslator) + val germanTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.germanTranslator) + val frenchCzechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchCzechTranslator) + val bobNotifications = notificationsRepository.findAllByRecipient(testData.bob) + + acmeChiefNotifications.assert.hasSize(1) + projectManagerNotifications.assert.hasSize(1) + frenchTranslatorNotifications.assert.hasSize(1) + czechTranslatorNotifications.assert.hasSize(0) + germanTranslatorNotifications.assert.hasSize(0) + frenchCzechTranslatorNotifications.assert.hasSize(1) + bobNotifications.assert.hasSize(1) + + ensureNoNotificationDispatch() + } + + @Test + fun `it does dispatch notifications with trimmed data to people who can only see part of the changes`() { + performAuthPut( + url = "/v2/projects/${testData.project1.id}/translations", + content = SetTranslationsWithKeyDto( + key = testData.keyProject1.name, + translations = mapOf("fr" to "Superb French translation!", "cs" to "Superb Czech translation!") + ) + ).andIsOk + + waitUntilNotificationDispatch(6) + val acmeChiefNotifications = notificationsRepository.findAllByRecipient(testData.orgAdmin) + val projectManagerNotifications = notificationsRepository.findAllByRecipient(testData.projectManager) + val frenchTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchTranslator) + val czechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.czechTranslator) + val germanTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.germanTranslator) + val frenchCzechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchCzechTranslator) + val bobNotifications = notificationsRepository.findAllByRecipient(testData.bob) + + acmeChiefNotifications.assert.hasSize(1) + projectManagerNotifications.assert.hasSize(1) + frenchTranslatorNotifications.assert.hasSize(1) + czechTranslatorNotifications.assert.hasSize(1) + germanTranslatorNotifications.assert.hasSize(0) + frenchCzechTranslatorNotifications.assert.hasSize(1) + bobNotifications.assert.hasSize(1) + + acmeChiefNotifications[0].activityModifiedEntities.assert.hasSize(2) + projectManagerNotifications[0].activityModifiedEntities.assert.hasSize(2) + frenchTranslatorNotifications[0].activityModifiedEntities.assert.hasSize(1) + czechTranslatorNotifications[0].activityModifiedEntities.assert.hasSize(1) + frenchCzechTranslatorNotifications[0].activityModifiedEntities.assert.hasSize(2) + bobNotifications[0].activityModifiedEntities.assert.hasSize(2) + + frenchTranslatorNotifications[0].activityModifiedEntities.first() + .entityId.assert.isEqualTo(testData.key1FrTranslation.id) + + czechTranslatorNotifications[0].activityModifiedEntities.first() + .entityId.assert.isEqualTo(testData.key1CzTranslation.id) + + ensureNoNotificationDispatch() + } + + @Test + fun `it does properly compute metadata for import-related notifications`() { + performAuthMultipart( + url = "/v2/projects/${testData.project1.id}/import", + files = listOf( + MockMultipartFile( + "files", "en.json", "application/json", + """ {"new-key1": "New string 1", "new-key2": "New string 2"} """.toByteArray() + ), + MockMultipartFile( + "files", "fr.json", "application/json", + """ {"new-key1": "New FR string 1", "new-key2": "New FR string 2"} """.toByteArray() + ), + MockMultipartFile( + "files", "cs.json", "application/json", + """ {"new-key1": "New CZ string 1", "new-key2": "New CZ string 2"} """.toByteArray() + ) + ) + ).andIsOk + + performAuthPut("/v2/projects/${testData.project1.id}/import/apply", null).andIsOk + + waitUntilNotificationDispatch(7) + val acmeChiefNotifications = notificationsRepository.findAllByRecipient(testData.orgAdmin) + val projectManagerNotifications = notificationsRepository.findAllByRecipient(testData.projectManager) + val frenchTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchTranslator) + val czechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.czechTranslator) + val germanTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.germanTranslator) + val frenchCzechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchCzechTranslator) + val bobNotifications = notificationsRepository.findAllByRecipient(testData.bob) + + acmeChiefNotifications.assert.hasSize(1) + projectManagerNotifications.assert.hasSize(1) + frenchTranslatorNotifications.assert.hasSize(1) + czechTranslatorNotifications.assert.hasSize(1) + germanTranslatorNotifications.assert.hasSize(1) + frenchCzechTranslatorNotifications.assert.hasSize(1) + bobNotifications.assert.hasSize(1) + + acmeChiefNotifications[0].meta.assert.isEqualTo( + mapOf("keysCount" to 2, "translationsCount" to 6) + ) + projectManagerNotifications[0].meta.assert.isEqualTo( + mapOf("keysCount" to 2, "translationsCount" to 6) + ) + frenchTranslatorNotifications[0].meta.assert.isEqualTo( + mapOf("keysCount" to 2, "translationsCount" to 4) + ) + czechTranslatorNotifications[0].meta.assert.isEqualTo( + mapOf("keysCount" to 2, "translationsCount" to 4) + ) + germanTranslatorNotifications[0].meta.assert.isEqualTo( + mapOf("keysCount" to 2, "translationsCount" to 2) + ) + frenchCzechTranslatorNotifications[0].meta.assert.isEqualTo( + mapOf("keysCount" to 2, "translationsCount" to 6) + ) + bobNotifications[0].meta.assert.isEqualTo( + mapOf("keysCount" to 2, "translationsCount" to 6) + ) + + ensureNoNotificationDispatch() + } + + @Test + fun `it does not dispatch modifications to the responsible user`() { + loginAsUser(testData.projectManager) performAuthPost( "/v2/projects/${testData.project1.id}/keys/create", CreateKeyDto(name = "test-key") @@ -76,6 +246,7 @@ class NotificationDispatchTest : AuthorizedControllerTest() { waitUntilNotificationDispatch(6) val adminNotifications = notificationsRepository.findAllByRecipient(testData.admin) + val acmeChiefNotifications = notificationsRepository.findAllByRecipient(testData.orgAdmin) val projectManagerNotifications = notificationsRepository.findAllByRecipient(testData.projectManager) val frenchTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchTranslator) val czechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.czechTranslator) @@ -85,26 +256,15 @@ class NotificationDispatchTest : AuthorizedControllerTest() { val aliceNotifications = notificationsRepository.findAllByRecipient(testData.alice) adminNotifications.assert.hasSize(0) - projectManagerNotifications.assert.hasSize(1) + acmeChiefNotifications.assert.hasSize(1) + projectManagerNotifications.assert.hasSize(0) frenchTranslatorNotifications.assert.hasSize(1) czechTranslatorNotifications.assert.hasSize(1) germanTranslatorNotifications.assert.hasSize(1) frenchCzechTranslatorNotifications.assert.hasSize(1) bobNotifications.assert.hasSize(1) aliceNotifications.assert.hasSize(0) - } - - private fun waitUntilNotificationDispatch(count: Int = 1) { - val dispatched = semaphore.tryAcquire(count, 1L, TimeUnit.SECONDS) - dispatched.assert - .withFailMessage("Expected at least $count notification(s) to be dispatched.") - .isTrue() - } - private fun ensureNoNotificationDispatch() { - val dispatched = semaphore.tryAcquire(1L, TimeUnit.SECONDS) - dispatched.assert - .withFailMessage("Expected no notifications to be dispatched.") - .isFalse() + ensureNoNotificationDispatch() } } diff --git a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationsTestData.kt b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationsTestData.kt index b1cb8d36fe..64adfbfcfe 100644 --- a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationsTestData.kt +++ b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationsTestData.kt @@ -203,10 +203,14 @@ class NotificationsTestData { } // --- --- --- + addPermission { + user = projectManager + type = ProjectPermissionType.MANAGE + } addPermission { user = frenchTranslator - type = ProjectPermissionType.REVIEW + type = ProjectPermissionType.EDIT viewLanguages.add(en.self) viewLanguages.add(fr.self) translateLanguages.add(en.self) @@ -217,7 +221,7 @@ class NotificationsTestData { addPermission { user = czechTranslator - type = ProjectPermissionType.REVIEW + type = ProjectPermissionType.EDIT viewLanguages.add(en.self) viewLanguages.add(cz.self) translateLanguages.add(en.self) @@ -228,7 +232,7 @@ class NotificationsTestData { addPermission { user = germanTranslator - type = ProjectPermissionType.REVIEW + type = ProjectPermissionType.EDIT viewLanguages.add(en.self) viewLanguages.add(de.self) translateLanguages.add(en.self) @@ -239,7 +243,7 @@ class NotificationsTestData { addPermission { user = frenchCzechTranslator - type = ProjectPermissionType.REVIEW + type = ProjectPermissionType.EDIT viewLanguages.add(en.self) viewLanguages.add(fr.self) viewLanguages.add(cz.self) diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationService.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationService.kt index 08ef06bd89..70b03ea650 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationService.kt @@ -24,7 +24,6 @@ import io.tolgee.notifications.events.NotificationUserPushEvent import io.tolgee.repository.NotificationsRepository import org.springframework.context.ApplicationEventPublisher import org.springframework.data.domain.Pageable -import org.springframework.scheduling.annotation.Async import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import java.util.* @@ -34,13 +33,11 @@ class NotificationService( private val notificationsRepository: NotificationsRepository, private val applicationEventPublisher: ApplicationEventPublisher, ) { - @Async @Transactional fun dispatchNotification(notificationDto: NotificationCreateDto, params: NotificationDispatchParamsDto) { return dispatchNotifications(notificationDto, listOf(params)) } - @Async @Transactional fun dispatchNotifications(notificationDto: NotificationCreateDto, params: List) { val notificationObjects = mutableSetOf() diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt index f8510ee2b0..84643b87d5 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt @@ -31,6 +31,7 @@ import io.tolgee.service.security.UserAccountService import io.tolgee.util.Logging import io.tolgee.util.logger import org.springframework.context.event.EventListener +import org.springframework.scheduling.annotation.Async import org.springframework.stereotype.Component import javax.persistence.EntityManager @@ -42,6 +43,7 @@ class UserNotificationDispatch( private val notificationService: NotificationService, private val entityManager: EntityManager, ) : Logging { + @Async @EventListener fun onNotificationCreate(e: NotificationCreateEvent) { logger.trace("Received notification creation event {}", e) @@ -176,6 +178,9 @@ class UserNotificationDispatch( activityModifiedEntities = visibleModifiedEntities, ) } + .filter { + it.activityModifiedEntities.isNotEmpty() + } notificationService.dispatchNotifications(e.notification, dispatches) } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt index 45ec691fe8..bec1728368 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt @@ -77,8 +77,10 @@ data class NotificationCreateDto( if (activityRevision == null) throw IllegalArgumentException("Tried to merge notifications of incompatible type") if (notification.recipient.id != params.recipient.id) - throw IllegalArgumentException("Tried to merge a notification for user#${notification.recipient.id}, " + - "but specified ${params.recipient.id} as recipient in notification dispatch parameters") + throw IllegalArgumentException( + "Tried to merge a notification for user#${notification.recipient.id}, " + + "but specified ${params.recipient.id} as recipient in notification dispatch parameters" + ) notification.activityRevisions.add(activityRevision) params.activityModifiedEntities.forEach { diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt index ed7c05ff6f..8a0f7aa6fb 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt @@ -22,10 +22,10 @@ interface LanguageRepository : JpaRepository { @Query( """ - SELECT new map(t.id, t.language.id) + SELECT new map(t.id as translationId, t.language.id as languageId) FROM Translation t WHERE t.id IN :translationIds """ ) - fun findLanguageIdsOfTranslations(translationIds: List): List> + fun findLanguageIdsOfTranslations(translationIds: List): List> } diff --git a/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt b/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt index 6f39e7c156..10234567bc 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt @@ -159,7 +159,11 @@ class LanguageService( } fun findLanguageIdsOfTranslations(translationIds: List): Map { - return languageRepository.findLanguageIdsOfTranslations(translationIds) + val maps = languageRepository.findLanguageIdsOfTranslations(translationIds) + if (maps.isEmpty()) return emptyMap() + + return maps + .map { mapOf(it["translationId"]!! to it["languageId"]!!) } .reduce { acc, map -> acc.plus(map) } } diff --git a/backend/data/src/main/kotlin/io/tolgee/util/dateExt.kt b/backend/data/src/main/kotlin/io/tolgee/util/dateExt.kt index cc5e136ffa..351f59e8f9 100644 --- a/backend/data/src/main/kotlin/io/tolgee/util/dateExt.kt +++ b/backend/data/src/main/kotlin/io/tolgee/util/dateExt.kt @@ -26,6 +26,12 @@ fun Date.addSeconds(seconds: Int): Date { return calendar.time } +fun Date.addMilliseconds(milliseconds: Int): Date { + val calendar = toUtcCalendar() + calendar.add(Calendar.MILLISECOND, milliseconds) + return calendar.time +} + private fun Date.toUtcCalendar(): Calendar { val calendar = getUtcCalendar() calendar.time = this From 3b31359c059cbce0cc7ec0fdbb2f3cea0b071917 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Sun, 3 Dec 2023 10:55:24 +0100 Subject: [PATCH 08/44] feat: redo notifications the right way this time --- .../api/v2/controllers/KeyController.kt | 2 +- .../notifications/AbstractNotificationTest.kt | 38 ++- .../notifications/NotificationDispatchTest.kt | 270 ------------------ .../RemappedNotificationsTest.kt | 154 ++++++++++ .../UserNotificationDebounceTest.kt | 115 ++++++++ .../UserNotificationDispatchTest.kt | 201 +++++++++++++ .../data/NotificationsTestData.kt | 34 +++ .../dtos/request/key/KeyScreenshotDto.kt | 10 +- .../main/kotlin/io/tolgee/model/Project.kt | 2 +- .../kotlin/io/tolgee/model/UserAccount.kt | 2 +- .../{Notification.kt => UserNotification.kt} | 34 +-- .../tolgee/model/activity/ActivityRevision.kt | 1 - ...UserAccountProjectNotificationDataView.kt} | 23 +- .../notifications/NotificationService.kt | 109 ------- .../tolgee/notifications/NotificationType.kt | 56 ++++ .../UserNotificationDebouncer.kt | 117 ++++++++ .../notifications/UserNotificationService.kt | 90 ++++++ .../dispatchers/UserNotificationDispatch.kt | 231 +++++---------- .../dto/NotificationCreateDto.kt | 84 ++---- ...amsDto.kt => UserNotificationParamsDto.kt} | 5 +- .../events/NotificationCreateEvent.kt | 2 +- ...hEvent.kt => UserNotificationPushEvent.kt} | 4 +- .../listeners/ActivityEventListener.kt | 237 ++++++++++++++- .../listeners/BatchJobListener.kt | 109 +------ .../repository/NotificationsRepository.kt | 86 ------ .../repository/UserAccountRepository.kt | 6 +- .../repository/UserNotificationRepository.kt | 113 ++++++++ .../service/security/PermissionService.kt | 4 +- .../service/security/UserAccountService.kt | 4 +- .../main/resources/db/changelog/schema.xml | 57 ++-- .../io/tolgee/fixtures/statusExpectations.kt | 6 +- 31 files changed, 1311 insertions(+), 895 deletions(-) delete mode 100644 backend/app/src/test/kotlin/io/tolgee/notifications/NotificationDispatchTest.kt create mode 100644 backend/app/src/test/kotlin/io/tolgee/notifications/RemappedNotificationsTest.kt create mode 100644 backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt create mode 100644 backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDispatchTest.kt rename backend/data/src/main/kotlin/io/tolgee/model/{Notification.kt => UserNotification.kt} (72%) rename backend/data/src/main/kotlin/io/tolgee/model/views/{UserAccountProjectPermissionDataView.kt => UserAccountProjectNotificationDataView.kt} (65%) delete mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/NotificationService.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/NotificationType.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationDebouncer.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt rename backend/data/src/main/kotlin/io/tolgee/notifications/dto/{NotificationDispatchParamsDto.kt => UserNotificationParamsDto.kt} (81%) rename backend/data/src/main/kotlin/io/tolgee/notifications/events/{NotificationUserPushEvent.kt => UserNotificationPushEvent.kt} (86%) delete mode 100644 backend/data/src/main/kotlin/io/tolgee/repository/NotificationsRepository.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/repository/UserNotificationRepository.kt diff --git a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/KeyController.kt b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/KeyController.kt index 14e67ae6fc..b8f5032513 100644 --- a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/KeyController.kt +++ b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/KeyController.kt @@ -107,7 +107,7 @@ class KeyController( } @PutMapping(value = ["/{id}/complex-update"]) - @Operation(summary = "More") + @Operation(summary = "Performs more complex updates on multiple key properties and its translations at once") @UseDefaultPermissions // Security: key permissions are checked separately in method body @AllowApiAccess fun complexEdit(@PathVariable id: Long, @RequestBody @Valid dto: ComplexEditKeyDto): KeyWithDataModel { diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt index f06d1adfeb..7f0187d028 100644 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt @@ -16,7 +16,8 @@ package io.tolgee.notifications -import io.tolgee.repository.NotificationsRepository +import io.tolgee.development.testDataBuilder.data.NotificationsTestData +import io.tolgee.repository.UserNotificationRepository import io.tolgee.testing.AuthorizedControllerTest import io.tolgee.testing.assert import io.tolgee.util.addMilliseconds @@ -34,19 +35,23 @@ import java.util.concurrent.TimeUnit abstract class AbstractNotificationTest : AuthorizedControllerTest() { @Autowired - lateinit var notificationService: NotificationService + lateinit var userNotificationService: UserNotificationService @Autowired lateinit var taskScheduler: TaskScheduler @SpyBean @Autowired - lateinit var notificationsRepository: NotificationsRepository + lateinit var userNotificationRepository: UserNotificationRepository + lateinit var testData: NotificationsTestData lateinit var semaphore: Semaphore @BeforeEach - fun setupWatcher() { + fun setupTests() { + testData = NotificationsTestData() + testDataService.saveTestData(testData.root) + semaphore = Semaphore(0) doAnswer { @@ -63,22 +68,39 @@ abstract class AbstractNotificationTest : AuthorizedControllerTest() { ) it.arguments[0] - }.`when`(notificationsRepository).save(any()) + }.`when`(userNotificationRepository).save(any()) + + doAnswer { + val list = it.arguments[0] as List<*> + for (entity in list) entityManager.persist(entity) + entityManager.flush() + + for (entity in it.arguments[0] as List<*>) entityManager.refresh(entity) + + // Wait a bit to make sure everything's *actually* persisted + // Kind of an ugly way to synchronize everything, but it is what it is + taskScheduler.schedule( + { semaphore.release(list.size) }, + Date().addMilliseconds(100) + ) + + it.arguments[0] + }.`when`(userNotificationRepository).saveAll(Mockito.anyList()) } @AfterEach fun clearWatcher() { - Mockito.reset(notificationsRepository) + Mockito.reset(userNotificationRepository) } - fun waitUntilNotificationDispatch(count: Int = 1) { + fun waitUntilUserNotificationDispatch(count: Int = 1) { val dispatched = semaphore.tryAcquire(count, 2L, TimeUnit.SECONDS) dispatched.assert .withFailMessage("Expected at least $count notification(s) to be dispatched.") .isTrue() } - fun ensureNoNotificationDispatch() { + fun ensureNoUserNotificationDispatch() { val dispatched = semaphore.tryAcquire(2L, TimeUnit.SECONDS) dispatched.assert .withFailMessage("Expected no notifications to be dispatched.") diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/NotificationDispatchTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/NotificationDispatchTest.kt deleted file mode 100644 index b770e64aab..0000000000 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/NotificationDispatchTest.kt +++ /dev/null @@ -1,270 +0,0 @@ -/** - * Copyright (C) 2023 Tolgee s.r.o. and contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.tolgee.notifications - -import io.tolgee.development.testDataBuilder.data.NotificationsTestData -import io.tolgee.dtos.request.key.CreateKeyDto -import io.tolgee.dtos.request.translation.SetTranslationsWithKeyDto -import io.tolgee.fixtures.andIsCreated -import io.tolgee.fixtures.andIsOk -import io.tolgee.testing.assert -import io.tolgee.util.generateImage -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.springframework.mock.web.MockMultipartFile - -class NotificationDispatchTest : AbstractNotificationTest() { - lateinit var testData: NotificationsTestData - - @BeforeEach - fun createTestData() { - testData = NotificationsTestData() - testDataService.saveTestData(testData.root) - } - - @Test - fun `it dispatches notifications to everyone in project`() { - performAuthPost( - "/v2/projects/${testData.project1.id}/keys/create", - CreateKeyDto(name = "test-key") - ).andIsCreated - - waitUntilNotificationDispatch(7) - val adminNotifications = notificationsRepository.findAllByRecipient(testData.admin) - val acmeChiefNotifications = notificationsRepository.findAllByRecipient(testData.orgAdmin) - val projectManagerNotifications = notificationsRepository.findAllByRecipient(testData.projectManager) - val frenchTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchTranslator) - val czechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.czechTranslator) - val germanTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.germanTranslator) - val frenchCzechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchCzechTranslator) - val bobNotifications = notificationsRepository.findAllByRecipient(testData.bob) - val aliceNotifications = notificationsRepository.findAllByRecipient(testData.alice) - - adminNotifications.assert.hasSize(0) - acmeChiefNotifications.assert.hasSize(1) - projectManagerNotifications.assert.hasSize(1) - frenchTranslatorNotifications.assert.hasSize(1) - czechTranslatorNotifications.assert.hasSize(1) - germanTranslatorNotifications.assert.hasSize(1) - frenchCzechTranslatorNotifications.assert.hasSize(1) - bobNotifications.assert.hasSize(1) - aliceNotifications.assert.hasSize(0) - - ensureNoNotificationDispatch() - } - - @Test - fun `it does not dispatch notifications to people without the permission to see the change`() { - performAuthMultipart( - url = "/v2/projects/${testData.project1.id}/keys/${testData.keyProject1.id}/screenshots", - files = listOf( - MockMultipartFile( - "screenshot", "originalShot.png", "image/png", - generateImage(100, 100).inputStream.readAllBytes() - ) - ) - ).andIsCreated - - waitUntilNotificationDispatch(6) - val acmeChiefNotifications = notificationsRepository.findAllByRecipient(testData.orgAdmin) - val projectManagerNotifications = notificationsRepository.findAllByRecipient(testData.projectManager) - val frenchTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchTranslator) - val czechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.czechTranslator) - val germanTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.germanTranslator) - val frenchCzechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchCzechTranslator) - val bobNotifications = notificationsRepository.findAllByRecipient(testData.bob) - - acmeChiefNotifications.assert.hasSize(1) - projectManagerNotifications.assert.hasSize(1) - frenchTranslatorNotifications.assert.hasSize(1) - czechTranslatorNotifications.assert.hasSize(1) - germanTranslatorNotifications.assert.hasSize(1) - frenchCzechTranslatorNotifications.assert.hasSize(1) - bobNotifications.assert.hasSize(0) - - ensureNoNotificationDispatch() - } - - @Test - fun `it does not dispatch notifications to people without the permission to see the target language`() { - performAuthPut( - url = "/v2/projects/${testData.project1.id}/translations", - content = SetTranslationsWithKeyDto( - key = testData.keyProject1.name, - translations = mapOf("fr" to "Superb French translation!") - ) - ).andIsOk - - waitUntilNotificationDispatch(5) - val acmeChiefNotifications = notificationsRepository.findAllByRecipient(testData.orgAdmin) - val projectManagerNotifications = notificationsRepository.findAllByRecipient(testData.projectManager) - val frenchTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchTranslator) - val czechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.czechTranslator) - val germanTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.germanTranslator) - val frenchCzechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchCzechTranslator) - val bobNotifications = notificationsRepository.findAllByRecipient(testData.bob) - - acmeChiefNotifications.assert.hasSize(1) - projectManagerNotifications.assert.hasSize(1) - frenchTranslatorNotifications.assert.hasSize(1) - czechTranslatorNotifications.assert.hasSize(0) - germanTranslatorNotifications.assert.hasSize(0) - frenchCzechTranslatorNotifications.assert.hasSize(1) - bobNotifications.assert.hasSize(1) - - ensureNoNotificationDispatch() - } - - @Test - fun `it does dispatch notifications with trimmed data to people who can only see part of the changes`() { - performAuthPut( - url = "/v2/projects/${testData.project1.id}/translations", - content = SetTranslationsWithKeyDto( - key = testData.keyProject1.name, - translations = mapOf("fr" to "Superb French translation!", "cs" to "Superb Czech translation!") - ) - ).andIsOk - - waitUntilNotificationDispatch(6) - val acmeChiefNotifications = notificationsRepository.findAllByRecipient(testData.orgAdmin) - val projectManagerNotifications = notificationsRepository.findAllByRecipient(testData.projectManager) - val frenchTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchTranslator) - val czechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.czechTranslator) - val germanTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.germanTranslator) - val frenchCzechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchCzechTranslator) - val bobNotifications = notificationsRepository.findAllByRecipient(testData.bob) - - acmeChiefNotifications.assert.hasSize(1) - projectManagerNotifications.assert.hasSize(1) - frenchTranslatorNotifications.assert.hasSize(1) - czechTranslatorNotifications.assert.hasSize(1) - germanTranslatorNotifications.assert.hasSize(0) - frenchCzechTranslatorNotifications.assert.hasSize(1) - bobNotifications.assert.hasSize(1) - - acmeChiefNotifications[0].activityModifiedEntities.assert.hasSize(2) - projectManagerNotifications[0].activityModifiedEntities.assert.hasSize(2) - frenchTranslatorNotifications[0].activityModifiedEntities.assert.hasSize(1) - czechTranslatorNotifications[0].activityModifiedEntities.assert.hasSize(1) - frenchCzechTranslatorNotifications[0].activityModifiedEntities.assert.hasSize(2) - bobNotifications[0].activityModifiedEntities.assert.hasSize(2) - - frenchTranslatorNotifications[0].activityModifiedEntities.first() - .entityId.assert.isEqualTo(testData.key1FrTranslation.id) - - czechTranslatorNotifications[0].activityModifiedEntities.first() - .entityId.assert.isEqualTo(testData.key1CzTranslation.id) - - ensureNoNotificationDispatch() - } - - @Test - fun `it does properly compute metadata for import-related notifications`() { - performAuthMultipart( - url = "/v2/projects/${testData.project1.id}/import", - files = listOf( - MockMultipartFile( - "files", "en.json", "application/json", - """ {"new-key1": "New string 1", "new-key2": "New string 2"} """.toByteArray() - ), - MockMultipartFile( - "files", "fr.json", "application/json", - """ {"new-key1": "New FR string 1", "new-key2": "New FR string 2"} """.toByteArray() - ), - MockMultipartFile( - "files", "cs.json", "application/json", - """ {"new-key1": "New CZ string 1", "new-key2": "New CZ string 2"} """.toByteArray() - ) - ) - ).andIsOk - - performAuthPut("/v2/projects/${testData.project1.id}/import/apply", null).andIsOk - - waitUntilNotificationDispatch(7) - val acmeChiefNotifications = notificationsRepository.findAllByRecipient(testData.orgAdmin) - val projectManagerNotifications = notificationsRepository.findAllByRecipient(testData.projectManager) - val frenchTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchTranslator) - val czechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.czechTranslator) - val germanTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.germanTranslator) - val frenchCzechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchCzechTranslator) - val bobNotifications = notificationsRepository.findAllByRecipient(testData.bob) - - acmeChiefNotifications.assert.hasSize(1) - projectManagerNotifications.assert.hasSize(1) - frenchTranslatorNotifications.assert.hasSize(1) - czechTranslatorNotifications.assert.hasSize(1) - germanTranslatorNotifications.assert.hasSize(1) - frenchCzechTranslatorNotifications.assert.hasSize(1) - bobNotifications.assert.hasSize(1) - - acmeChiefNotifications[0].meta.assert.isEqualTo( - mapOf("keysCount" to 2, "translationsCount" to 6) - ) - projectManagerNotifications[0].meta.assert.isEqualTo( - mapOf("keysCount" to 2, "translationsCount" to 6) - ) - frenchTranslatorNotifications[0].meta.assert.isEqualTo( - mapOf("keysCount" to 2, "translationsCount" to 4) - ) - czechTranslatorNotifications[0].meta.assert.isEqualTo( - mapOf("keysCount" to 2, "translationsCount" to 4) - ) - germanTranslatorNotifications[0].meta.assert.isEqualTo( - mapOf("keysCount" to 2, "translationsCount" to 2) - ) - frenchCzechTranslatorNotifications[0].meta.assert.isEqualTo( - mapOf("keysCount" to 2, "translationsCount" to 6) - ) - bobNotifications[0].meta.assert.isEqualTo( - mapOf("keysCount" to 2, "translationsCount" to 6) - ) - - ensureNoNotificationDispatch() - } - - @Test - fun `it does not dispatch modifications to the responsible user`() { - loginAsUser(testData.projectManager) - performAuthPost( - "/v2/projects/${testData.project1.id}/keys/create", - CreateKeyDto(name = "test-key") - ).andIsCreated - - waitUntilNotificationDispatch(6) - val adminNotifications = notificationsRepository.findAllByRecipient(testData.admin) - val acmeChiefNotifications = notificationsRepository.findAllByRecipient(testData.orgAdmin) - val projectManagerNotifications = notificationsRepository.findAllByRecipient(testData.projectManager) - val frenchTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchTranslator) - val czechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.czechTranslator) - val germanTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.germanTranslator) - val frenchCzechTranslatorNotifications = notificationsRepository.findAllByRecipient(testData.frenchCzechTranslator) - val bobNotifications = notificationsRepository.findAllByRecipient(testData.bob) - val aliceNotifications = notificationsRepository.findAllByRecipient(testData.alice) - - adminNotifications.assert.hasSize(0) - acmeChiefNotifications.assert.hasSize(1) - projectManagerNotifications.assert.hasSize(0) - frenchTranslatorNotifications.assert.hasSize(1) - czechTranslatorNotifications.assert.hasSize(1) - germanTranslatorNotifications.assert.hasSize(1) - frenchCzechTranslatorNotifications.assert.hasSize(1) - bobNotifications.assert.hasSize(1) - aliceNotifications.assert.hasSize(0) - - ensureNoNotificationDispatch() - } -} diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/RemappedNotificationsTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/RemappedNotificationsTest.kt new file mode 100644 index 0000000000..d183c1738b --- /dev/null +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/RemappedNotificationsTest.kt @@ -0,0 +1,154 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.notifications + +import io.tolgee.dtos.request.key.ComplexEditKeyDto +import io.tolgee.dtos.request.key.KeyScreenshotDto +import io.tolgee.fixtures.andGetContentAsJsonMap +import io.tolgee.fixtures.andIsCreated +import io.tolgee.fixtures.andIsOk +import io.tolgee.testing.assert +import io.tolgee.util.generateImage +import org.junit.jupiter.api.Test +import org.springframework.mock.web.MockMultipartFile + +class RemappedNotificationsTest : AbstractNotificationTest() { + @Test + fun `it does properly remap imports to key and translation notifications`() { + performAuthMultipart( + url = "/v2/projects/${testData.project1.id}/import", + files = listOf( + MockMultipartFile( + "files", "en.json", "application/json", + """{"new-key1": "New string 1", "new-key2": "New string 2"}""".toByteArray() + ), + MockMultipartFile( + "files", "fr.json", "application/json", + """{"some-key": "Updated", "new-key1": "New FR string 1", "new-key2": "New FR string 2"}""".toByteArray() + ), + MockMultipartFile( + "files", "cs.json", "application/json", + """{"new-key1": "New CZ string 1", "new-key2": "New CZ string 2"}""".toByteArray() + ) + ) + ).andIsOk + + performAuthPut("/v2/projects/${testData.project1.id}/import/apply?forceMode=OVERRIDE", null).andIsOk + + waitUntilUserNotificationDispatch(14) + val acmeChiefNotifications = userNotificationRepository.findAllByRecipient(testData.orgAdmin) + val projectManagerNotifications = userNotificationRepository.findAllByRecipient(testData.projectManager) + val frenchTranslatorNotifications = userNotificationRepository.findAllByRecipient(testData.frenchTranslator) + val czechTranslatorNotifications = userNotificationRepository.findAllByRecipient(testData.czechTranslator) + val germanTranslatorNotifications = userNotificationRepository.findAllByRecipient(testData.germanTranslator) + val frenchCzechTranslatorNotifications = + userNotificationRepository.findAllByRecipient(testData.frenchCzechTranslator) + val bobNotifications = userNotificationRepository.findAllByRecipient(testData.bob) + + acmeChiefNotifications.assert.hasSize(2) + projectManagerNotifications.assert.hasSize(2) + frenchTranslatorNotifications.assert.hasSize(2) + czechTranslatorNotifications.assert.hasSize(2) + germanTranslatorNotifications.assert.hasSize(2) + frenchCzechTranslatorNotifications.assert.hasSize(2) + bobNotifications.assert.hasSize(2) + + acmeChiefNotifications.find { it.type == NotificationType.ACTIVITY_KEYS_CREATED }!! + .modifiedEntities.assert.hasSize(2) + acmeChiefNotifications.find { it.type == NotificationType.ACTIVITY_TRANSLATIONS_UPDATED }!! + .modifiedEntities.assert.hasSize(7) + + projectManagerNotifications.find { it.type == NotificationType.ACTIVITY_KEYS_CREATED }!! + .modifiedEntities.assert.hasSize(2) + projectManagerNotifications.find { it.type == NotificationType.ACTIVITY_TRANSLATIONS_UPDATED }!! + .modifiedEntities.assert.hasSize(7) + + frenchTranslatorNotifications.find { it.type == NotificationType.ACTIVITY_KEYS_CREATED }!! + .modifiedEntities.assert.hasSize(2) + frenchTranslatorNotifications.find { it.type == NotificationType.ACTIVITY_TRANSLATIONS_UPDATED }!! + .modifiedEntities.assert.hasSize(5) + + czechTranslatorNotifications.find { it.type == NotificationType.ACTIVITY_KEYS_CREATED }!! + .modifiedEntities.assert.hasSize(2) + czechTranslatorNotifications.find { it.type == NotificationType.ACTIVITY_TRANSLATIONS_UPDATED }!! + .modifiedEntities.assert.hasSize(4) + + germanTranslatorNotifications.find { it.type == NotificationType.ACTIVITY_KEYS_CREATED }!! + .modifiedEntities.assert.hasSize(2) + germanTranslatorNotifications.find { it.type == NotificationType.ACTIVITY_TRANSLATIONS_UPDATED }!! + .modifiedEntities.assert.hasSize(2) + + frenchCzechTranslatorNotifications.find { it.type == NotificationType.ACTIVITY_KEYS_CREATED }!! + .modifiedEntities.assert.hasSize(2) + frenchCzechTranslatorNotifications.find { it.type == NotificationType.ACTIVITY_TRANSLATIONS_UPDATED }!! + .modifiedEntities.assert.hasSize(7) + + bobNotifications.find { it.type == NotificationType.ACTIVITY_KEYS_CREATED }!! + .modifiedEntities.assert.hasSize(2) + bobNotifications.find { it.type == NotificationType.ACTIVITY_TRANSLATIONS_UPDATED }!! + .modifiedEntities.assert.hasSize(7) + + ensureNoUserNotificationDispatch() + } + + @Test + fun `it does remap complex key edits to relevant notification types`() { + val screenshotId = performAuthMultipart( + url = "/v2/image-upload", + files = listOf( + MockMultipartFile( + "image", "image.png", "image/png", + generateImage(100, 100).inputStream.readAllBytes() + ) + ) + ).andIsCreated.andGetContentAsJsonMap["id"] as Long + + performAuthPut( + "/v2/projects/${testData.project1.id}/keys/${testData.keyProject1.id}/complex-update", + ComplexEditKeyDto( + name = "new-name", + namespace = "new-namespace", + translations = mapOf("en" to "New EN string", "fr" to "New FR string"), + screenshotsToAdd = listOf( + KeyScreenshotDto(uploadedImageId = screenshotId) + ) + ) + ).andIsOk + + waitUntilUserNotificationDispatch(20) + val acmeChiefNotifications = userNotificationRepository.findAllByRecipient(testData.orgAdmin) + val czechTranslatorNotifications = userNotificationRepository.findAllByRecipient(testData.czechTranslator) + val bobNotifications = userNotificationRepository.findAllByRecipient(testData.bob) + + bobNotifications.assert + .hasSize(2) + .noneMatch { it.type == NotificationType.ACTIVITY_KEYS_SCREENSHOTS_UPLOADED } + + acmeChiefNotifications.assert + .hasSize(3) + .anyMatch { it.type == NotificationType.ACTIVITY_KEYS_UPDATED } + .anyMatch { it.type == NotificationType.ACTIVITY_KEYS_SCREENSHOTS_UPLOADED } + .anyMatch { it.type == NotificationType.ACTIVITY_TRANSLATIONS_UPDATED && it.modifiedEntities.size == 2 } + + czechTranslatorNotifications.assert.hasSize(3) + .anyMatch { it.type == NotificationType.ACTIVITY_KEYS_UPDATED } + .anyMatch { it.type == NotificationType.ACTIVITY_KEYS_SCREENSHOTS_UPLOADED } + .anyMatch { it.type == NotificationType.ACTIVITY_TRANSLATIONS_UPDATED && it.modifiedEntities.size == 1 } + + ensureNoUserNotificationDispatch() + } +} diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt new file mode 100644 index 0000000000..f8cefd8f10 --- /dev/null +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt @@ -0,0 +1,115 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.notifications + +import io.tolgee.dtos.request.key.CreateKeyDto +import io.tolgee.dtos.request.translation.SetTranslationsWithKeyDto +import io.tolgee.dtos.request.translation.comment.TranslationCommentWithLangKeyDto +import io.tolgee.fixtures.andIsCreated +import io.tolgee.fixtures.andIsOk +import io.tolgee.testing.assert +import org.junit.jupiter.api.Test + +class UserNotificationDebounceTest : AbstractNotificationTest() { + @Test + fun `it debounces notifications of the same type`() { + performAuthPost( + "/v2/projects/${testData.calmProject.id}/keys/create", + CreateKeyDto(name = "test-key-1") + ).andIsCreated + + waitUntilUserNotificationDispatch() + userNotificationRepository.findAllByRecipient(testData.alice).assert.hasSize(1) + + performAuthPost( + "/v2/projects/${testData.calmProject.id}/keys/create", + CreateKeyDto(name = "test-key-2") + ).andIsCreated + + waitUntilUserNotificationDispatch() + userNotificationRepository.findAllByRecipient(testData.alice).assert.hasSize(1) + + performAuthPut( + url = "/v2/projects/${testData.calmProject.id}/translations", + content = SetTranslationsWithKeyDto( + key = testData.keyCalmProject.name, + translations = mapOf("fr" to "Superb French translation!") + ) + ).andIsOk + + waitUntilUserNotificationDispatch() + userNotificationRepository.findAllByRecipient(testData.alice).assert.hasSize(2) + } + + @Test + fun `it only debounces notifications within the same project`() { + performAuthPost( + "/v2/projects/${testData.calmProject.id}/keys/create", + CreateKeyDto(name = "test-key-1") + ).andIsCreated + + waitUntilUserNotificationDispatch() + userNotificationRepository.findAllByRecipient(testData.alice).assert.hasSize(1) + + performAuthPost( + "/v2/projects/${testData.project2.id}/keys/create", + CreateKeyDto(name = "test-key-2") + ).andIsCreated + + waitUntilUserNotificationDispatch() + userNotificationRepository.findAllByRecipient(testData.alice).assert.hasSize(2) + } + + @Test + fun `it debounces comments only when they are under the same translation`() { + performAuthPost( + "/v2/projects/${testData.calmProject.id}/translations/create-comment", + TranslationCommentWithLangKeyDto( + keyId = testData.keyCalmProject.id, + languageId = testData.keyCalmEnTranslation.language.id, + text = "This is a test" + ) + ).andIsCreated + + waitUntilUserNotificationDispatch() + userNotificationRepository.findAllByRecipient(testData.alice).assert.hasSize(1) + + performAuthPost( + "/v2/projects/${testData.calmProject.id}/translations/create-comment", + TranslationCommentWithLangKeyDto( + keyId = testData.keyCalmProject.id, + languageId = testData.keyCalmEnTranslation.language.id, + text = "This is a test 2" + ) + ).andIsCreated + + waitUntilUserNotificationDispatch() + userNotificationRepository.findAllByRecipient(testData.alice).assert.hasSize(1) + + performAuthPost( + "/v2/projects/${testData.calmProject.id}/translations/create-comment", + TranslationCommentWithLangKeyDto( + keyId = testData.keyCalmProject.id, + languageId = testData.calmProjectFr.id, + text = "This is a test" + ) + ).andIsCreated + + waitUntilUserNotificationDispatch() + userNotificationRepository.findAllByRecipient(testData.alice).assert.hasSize(2) + } +} diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDispatchTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDispatchTest.kt new file mode 100644 index 0000000000..3e6e391b18 --- /dev/null +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDispatchTest.kt @@ -0,0 +1,201 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.notifications + +import io.tolgee.dtos.request.key.CreateKeyDto +import io.tolgee.dtos.request.translation.SetTranslationsWithKeyDto +import io.tolgee.fixtures.andIsCreated +import io.tolgee.fixtures.andIsOk +import io.tolgee.testing.assert +import io.tolgee.util.generateImage +import org.junit.jupiter.api.Test +import org.springframework.mock.web.MockMultipartFile + +class UserNotificationDispatchTest : AbstractNotificationTest() { + @Test + fun `it dispatches notifications to everyone in project`() { + performAuthPost( + "/v2/projects/${testData.project1.id}/keys/create", + CreateKeyDto(name = "test-key") + ).andIsCreated + + waitUntilUserNotificationDispatch(7) + val adminNotifications = userNotificationRepository.findAllByRecipient(testData.admin) + val acmeChiefNotifications = userNotificationRepository.findAllByRecipient(testData.orgAdmin) + val projectManagerNotifications = userNotificationRepository.findAllByRecipient(testData.projectManager) + val frenchTranslatorNotifications = userNotificationRepository.findAllByRecipient(testData.frenchTranslator) + val czechTranslatorNotifications = userNotificationRepository.findAllByRecipient(testData.czechTranslator) + val germanTranslatorNotifications = userNotificationRepository.findAllByRecipient(testData.germanTranslator) + val frenchCzechTranslatorNotifications = + userNotificationRepository.findAllByRecipient(testData.frenchCzechTranslator) + val bobNotifications = userNotificationRepository.findAllByRecipient(testData.bob) + val aliceNotifications = userNotificationRepository.findAllByRecipient(testData.alice) + + adminNotifications.assert.hasSize(0) + acmeChiefNotifications.assert.hasSize(1) + projectManagerNotifications.assert.hasSize(1) + frenchTranslatorNotifications.assert.hasSize(1) + czechTranslatorNotifications.assert.hasSize(1) + germanTranslatorNotifications.assert.hasSize(1) + frenchCzechTranslatorNotifications.assert.hasSize(1) + bobNotifications.assert.hasSize(1) + aliceNotifications.assert.hasSize(0) + + ensureNoUserNotificationDispatch() + } + + @Test + fun `it does not dispatch notifications to people without the permission to see the change`() { + performAuthMultipart( + url = "/v2/projects/${testData.project1.id}/keys/${testData.keyProject1.id}/screenshots", + files = listOf( + MockMultipartFile( + "screenshot", "originalShot.png", "image/png", + generateImage(100, 100).inputStream.readAllBytes() + ) + ) + ).andIsCreated + + waitUntilUserNotificationDispatch(6) + val acmeChiefNotifications = userNotificationRepository.findAllByRecipient(testData.orgAdmin) + val projectManagerNotifications = userNotificationRepository.findAllByRecipient(testData.projectManager) + val frenchTranslatorNotifications = userNotificationRepository.findAllByRecipient(testData.frenchTranslator) + val czechTranslatorNotifications = userNotificationRepository.findAllByRecipient(testData.czechTranslator) + val germanTranslatorNotifications = userNotificationRepository.findAllByRecipient(testData.germanTranslator) + val frenchCzechTranslatorNotifications = + userNotificationRepository.findAllByRecipient(testData.frenchCzechTranslator) + val bobNotifications = userNotificationRepository.findAllByRecipient(testData.bob) + + acmeChiefNotifications.assert.hasSize(1) + projectManagerNotifications.assert.hasSize(1) + frenchTranslatorNotifications.assert.hasSize(1) + czechTranslatorNotifications.assert.hasSize(1) + germanTranslatorNotifications.assert.hasSize(1) + frenchCzechTranslatorNotifications.assert.hasSize(1) + bobNotifications.assert.hasSize(0) + + ensureNoUserNotificationDispatch() + } + + @Test + fun `it does not dispatch notifications to people without the permission to see the target language`() { + performAuthPut( + url = "/v2/projects/${testData.project1.id}/translations", + content = SetTranslationsWithKeyDto( + key = testData.keyProject1.name, + translations = mapOf("fr" to "Superb French translation!") + ) + ).andIsOk + + waitUntilUserNotificationDispatch(5) + val acmeChiefNotifications = userNotificationRepository.findAllByRecipient(testData.orgAdmin) + val projectManagerNotifications = userNotificationRepository.findAllByRecipient(testData.projectManager) + val frenchTranslatorNotifications = userNotificationRepository.findAllByRecipient(testData.frenchTranslator) + val czechTranslatorNotifications = userNotificationRepository.findAllByRecipient(testData.czechTranslator) + val germanTranslatorNotifications = userNotificationRepository.findAllByRecipient(testData.germanTranslator) + val frenchCzechTranslatorNotifications = + userNotificationRepository.findAllByRecipient(testData.frenchCzechTranslator) + val bobNotifications = userNotificationRepository.findAllByRecipient(testData.bob) + + acmeChiefNotifications.assert.hasSize(1) + projectManagerNotifications.assert.hasSize(1) + frenchTranslatorNotifications.assert.hasSize(1) + czechTranslatorNotifications.assert.hasSize(0) + germanTranslatorNotifications.assert.hasSize(0) + frenchCzechTranslatorNotifications.assert.hasSize(1) + bobNotifications.assert.hasSize(1) + + ensureNoUserNotificationDispatch() + } + + @Test + fun `it does dispatch notifications with trimmed data to people who can only see part of the changes`() { + performAuthPut( + url = "/v2/projects/${testData.project1.id}/translations", + content = SetTranslationsWithKeyDto( + key = testData.keyProject1.name, + translations = mapOf("fr" to "Superb French translation!", "cs" to "Superb Czech translation!") + ) + ).andIsOk + + waitUntilUserNotificationDispatch(6) + val acmeChiefNotifications = userNotificationRepository.findAllByRecipient(testData.orgAdmin) + val projectManagerNotifications = userNotificationRepository.findAllByRecipient(testData.projectManager) + val frenchTranslatorNotifications = userNotificationRepository.findAllByRecipient(testData.frenchTranslator) + val czechTranslatorNotifications = userNotificationRepository.findAllByRecipient(testData.czechTranslator) + val germanTranslatorNotifications = userNotificationRepository.findAllByRecipient(testData.germanTranslator) + val frenchCzechTranslatorNotifications = + userNotificationRepository.findAllByRecipient(testData.frenchCzechTranslator) + val bobNotifications = userNotificationRepository.findAllByRecipient(testData.bob) + + acmeChiefNotifications.assert.hasSize(1) + projectManagerNotifications.assert.hasSize(1) + frenchTranslatorNotifications.assert.hasSize(1) + czechTranslatorNotifications.assert.hasSize(1) + germanTranslatorNotifications.assert.hasSize(0) + frenchCzechTranslatorNotifications.assert.hasSize(1) + bobNotifications.assert.hasSize(1) + + acmeChiefNotifications[0].modifiedEntities.assert.hasSize(2) + projectManagerNotifications[0].modifiedEntities.assert.hasSize(2) + frenchTranslatorNotifications[0].modifiedEntities.assert.hasSize(1) + czechTranslatorNotifications[0].modifiedEntities.assert.hasSize(1) + frenchCzechTranslatorNotifications[0].modifiedEntities.assert.hasSize(2) + bobNotifications[0].modifiedEntities.assert.hasSize(2) + + frenchTranslatorNotifications[0].modifiedEntities.first() + .entityId.assert.isEqualTo(testData.key1FrTranslation.id) + + czechTranslatorNotifications[0].modifiedEntities.first() + .entityId.assert.isEqualTo(testData.key1CzTranslation.id) + + ensureNoUserNotificationDispatch() + } + + @Test + fun `it does not dispatch modifications to the responsible user`() { + loginAsUser(testData.projectManager) + performAuthPost( + "/v2/projects/${testData.project1.id}/keys/create", + CreateKeyDto(name = "test-key") + ).andIsCreated + + waitUntilUserNotificationDispatch(6) + val adminNotifications = userNotificationRepository.findAllByRecipient(testData.admin) + val acmeChiefNotifications = userNotificationRepository.findAllByRecipient(testData.orgAdmin) + val projectManagerNotifications = userNotificationRepository.findAllByRecipient(testData.projectManager) + val frenchTranslatorNotifications = userNotificationRepository.findAllByRecipient(testData.frenchTranslator) + val czechTranslatorNotifications = userNotificationRepository.findAllByRecipient(testData.czechTranslator) + val germanTranslatorNotifications = userNotificationRepository.findAllByRecipient(testData.germanTranslator) + val frenchCzechTranslatorNotifications = + userNotificationRepository.findAllByRecipient(testData.frenchCzechTranslator) + val bobNotifications = userNotificationRepository.findAllByRecipient(testData.bob) + val aliceNotifications = userNotificationRepository.findAllByRecipient(testData.alice) + + adminNotifications.assert.hasSize(0) + acmeChiefNotifications.assert.hasSize(1) + projectManagerNotifications.assert.hasSize(0) + frenchTranslatorNotifications.assert.hasSize(1) + czechTranslatorNotifications.assert.hasSize(1) + germanTranslatorNotifications.assert.hasSize(1) + frenchCzechTranslatorNotifications.assert.hasSize(1) + bobNotifications.assert.hasSize(1) + aliceNotifications.assert.hasSize(0) + + ensureNoUserNotificationDispatch() + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationsTestData.kt b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationsTestData.kt index 64adfbfcfe..8848ff0d57 100644 --- a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationsTestData.kt +++ b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationsTestData.kt @@ -17,6 +17,7 @@ package io.tolgee.development.testDataBuilder.data import io.tolgee.development.testDataBuilder.builders.TestDataBuilder +import io.tolgee.model.Language import io.tolgee.model.Organization import io.tolgee.model.Project import io.tolgee.model.UserAccount @@ -44,6 +45,7 @@ class NotificationsTestData { lateinit var project1: Project lateinit var project2: Project + lateinit var calmProject: Project // A project with only Alice in it for less notification noise lateinit var keyProject1: Key lateinit var key1EnTranslation: Translation @@ -53,6 +55,11 @@ class NotificationsTestData { lateinit var keyProject2: Key lateinit var key2EnTranslation: Translation + lateinit var keyCalmProject: Key + lateinit var keyCalmEnTranslation: Translation + + lateinit var calmProjectFr: Language + val root: TestDataBuilder = TestDataBuilder() init { @@ -120,6 +127,33 @@ class NotificationsTestData { username = "alice" alice = this + }.build { + defaultOrganizationBuilder.let { + addProject { + name = "Calm project" + slug = "keep-it-cool" + organizationOwner = it.self + + calmProject = this + }.build { + val en = addEnglish() + calmProjectFr = addFrench().self + + val key = addKey { + name = "some-key" + + this@NotificationsTestData.keyCalmProject = this@addKey + } + + addTranslation { + this.key = key.self + language = en.self + text = "Some translation" + + this@NotificationsTestData.keyCalmEnTranslation = this@addTranslation + } + } + } } addOrganization { diff --git a/backend/data/src/main/kotlin/io/tolgee/dtos/request/key/KeyScreenshotDto.kt b/backend/data/src/main/kotlin/io/tolgee/dtos/request/key/KeyScreenshotDto.kt index 81c6fda269..878fdaed7b 100644 --- a/backend/data/src/main/kotlin/io/tolgee/dtos/request/key/KeyScreenshotDto.kt +++ b/backend/data/src/main/kotlin/io/tolgee/dtos/request/key/KeyScreenshotDto.kt @@ -3,9 +3,9 @@ package io.tolgee.dtos.request.key import io.swagger.v3.oas.annotations.media.Schema import io.tolgee.dtos.request.KeyInScreenshotPositionDto -class KeyScreenshotDto { - var text: String? = null +data class KeyScreenshotDto( + var text: String? = null, @Schema(description = "Ids of screenshot uploaded with /v2/image-upload endpoint") - var uploadedImageId: Long = 0 - var positions: List? = null -} + var uploadedImageId: Long = 0, + var positions: List? = null, +) diff --git a/backend/data/src/main/kotlin/io/tolgee/model/Project.kt b/backend/data/src/main/kotlin/io/tolgee/model/Project.kt index 005d68df7e..02438216f3 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/Project.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/Project.kt @@ -88,7 +88,7 @@ class Project( var namespaces: MutableList = mutableListOf() @OneToMany(fetch = FetchType.LAZY, cascade = [CascadeType.REMOVE], mappedBy = "project") - var notifications: MutableList = mutableListOf() + var userNotifications: MutableList = mutableListOf() @ActivityLoggedProp override var avatarHash: String? = null diff --git a/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt b/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt index 6bc8c0df6c..e75b0f6a34 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt @@ -95,7 +95,7 @@ data class UserAccount( var passwordChanged: Boolean = true @OneToMany(fetch = FetchType.LAZY, cascade = [CascadeType.REMOVE], mappedBy = "recipient") - var notifications: MutableList = mutableListOf() + var userNotifications: MutableList = mutableListOf() val isDeletable: Boolean get() = this.accountType != AccountType.MANAGED && !this.isInitialUser diff --git a/backend/data/src/main/kotlin/io/tolgee/model/Notification.kt b/backend/data/src/main/kotlin/io/tolgee/model/UserNotification.kt similarity index 72% rename from backend/data/src/main/kotlin/io/tolgee/model/Notification.kt rename to backend/data/src/main/kotlin/io/tolgee/model/UserNotification.kt index 4652800609..c03748e7ba 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/Notification.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/UserNotification.kt @@ -16,14 +16,10 @@ package io.tolgee.model -import com.vladmihalcea.hibernate.type.json.JsonBinaryType import io.tolgee.model.activity.ActivityModifiedEntity -import io.tolgee.model.activity.ActivityRevision import io.tolgee.model.batch.BatchJob +import io.tolgee.notifications.NotificationType import org.hibernate.annotations.ColumnDefault -import org.hibernate.annotations.Type -import org.hibernate.annotations.TypeDef -import org.hibernate.annotations.TypeDefs import org.hibernate.annotations.UpdateTimestamp import java.util.* import javax.persistence.Column @@ -44,17 +40,12 @@ import javax.persistence.Temporal import javax.persistence.TemporalType @Entity -@TypeDefs( - value = [ - TypeDef(name = "jsonb", typeClass = JsonBinaryType::class) - ] -) -class Notification( +class UserNotification( @Column(nullable = false) @Enumerated(EnumType.STRING) val type: NotificationType, - // This data is very likely to be useless: lazy + // This data is very likely to be useless when consuming the entity: lazy @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(nullable = false) val recipient: UserAccount, @@ -66,20 +57,12 @@ class Notification( // We most definitely need this to show the notification: eager @ManyToMany(fetch = FetchType.EAGER) - @JoinTable(name = "notification_activity_revisions") - val activityRevisions: MutableSet = mutableSetOf(), - - // We most definitely need this to show the notification: eager - @ManyToMany(fetch = FetchType.EAGER) - @JoinTable(name = "notification_activity_modified_entities") - val activityModifiedEntities: MutableSet = mutableSetOf(), + @JoinTable(name = "user_notification_modified_entities") + val modifiedEntities: MutableSet = mutableSetOf(), // We most definitely need this to show the notification: eager @ManyToOne(fetch = FetchType.EAGER) - val batchJob: BatchJob? = null, - - @Type(type = "jsonb") - val meta: MutableMap + val batchJob: BatchJob? = null ) { @Id @SequenceGenerator(name = "notification_seq", sequenceName = "sequence_notifications") @@ -97,9 +80,4 @@ class Notification( @UpdateTimestamp @Temporal(TemporalType.TIMESTAMP) val lastUpdated: Date = Date() - - enum class NotificationType { - ACTIVITY, - BATCH_JOB_FAILURE, - } } diff --git a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityRevision.kt b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityRevision.kt index 0e08d0a9ed..06b94dfb77 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityRevision.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityRevision.kt @@ -45,7 +45,6 @@ import javax.persistence.TemporalType value = [TypeDef(name = "jsonb", typeClass = JsonBinaryType::class)] ) class ActivityRevision : java.io.Serializable { - @Id @SequenceGenerator( name = "activitySequenceGenerator", diff --git a/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionDataView.kt b/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectNotificationDataView.kt similarity index 65% rename from backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionDataView.kt rename to backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectNotificationDataView.kt index 798980fb49..741904fab4 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionDataView.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectNotificationDataView.kt @@ -20,7 +20,7 @@ import io.tolgee.model.enums.OrganizationRoleType import io.tolgee.model.enums.ProjectPermissionType import io.tolgee.model.enums.Scope -class UserAccountProjectPermissionDataView( +class UserAccountProjectNotificationDataView( val id: Long, val projectId: Long, val organizationRole: OrganizationRoleType?, @@ -28,16 +28,15 @@ class UserAccountProjectPermissionDataView( basePermissionsGranular: Array>?, val permissionsBasic: ProjectPermissionType?, permissionsGranular: Array>?, - viewLanguageIdsConcatenated: String, + permittedViewLanguages: String?, ) { - // I hate Hibernate - it *requires* an Array> or complains... - val basePermissionsGranular: List? = basePermissionsGranular?.map { enumValueOf(it.name) } - val permissionsGranular: List? = permissionsGranular?.map { enumValueOf(it.name) } - - // And don't get me started on its array support ^^ - val permittedViewLanguages = viewLanguageIdsConcatenated - .split(',') - .filter { it.isNotEmpty() } - .map { it.toLong() } - .ifEmpty { null } + // My love for Hibernate have no limit 🥰🥰🥰 + val basePermissionsGranular = basePermissionsGranular?.map { enumValueOf(it.name) } + val permissionsGranular = permissionsGranular?.map { enumValueOf(it.name) } + val permittedViewLanguages = permittedViewLanguages?.let { + it.split(',') + .filter { part -> part.isNotEmpty() } + .map { part -> part.toLong() } + .ifEmpty { null } + } } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationService.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationService.kt deleted file mode 100644 index 70b03ea650..0000000000 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationService.kt +++ /dev/null @@ -1,109 +0,0 @@ -/** - * Copyright (C) 2023 Tolgee s.r.o. and contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.tolgee.notifications - -import io.tolgee.model.Notification -import io.tolgee.model.UserAccount -import io.tolgee.notifications.dto.NotificationCreateDto -import io.tolgee.notifications.dto.NotificationDispatchParamsDto -import io.tolgee.notifications.events.NotificationUserPushEvent -import io.tolgee.repository.NotificationsRepository -import org.springframework.context.ApplicationEventPublisher -import org.springframework.data.domain.Pageable -import org.springframework.stereotype.Service -import org.springframework.transaction.annotation.Transactional -import java.util.* - -@Service -class NotificationService( - private val notificationsRepository: NotificationsRepository, - private val applicationEventPublisher: ApplicationEventPublisher, -) { - @Transactional - fun dispatchNotification(notificationDto: NotificationCreateDto, params: NotificationDispatchParamsDto) { - return dispatchNotifications(notificationDto, listOf(params)) - } - - @Transactional - fun dispatchNotifications(notificationDto: NotificationCreateDto, params: List) { - val notificationObjects = mutableSetOf() - val users = params.map { it.recipient } - - val existingNotifications = - if (debouncedNotificationTypes.contains(notificationDto.type)) - notificationsRepository.findNotificationsToDebounceMappedByUser( - notificationDto.type, - notificationDto.project, - users, - ) - else emptyMap() - - params.forEach { - if (existingNotifications.containsKey(it.recipient.id)) { - val notification = existingNotifications[it.recipient.id]!! - notificationDto.mergeIntoNotificationEntity(notification, it) - - notificationObjects.add( - notificationsRepository.save(notification) - ) - } else { - val notification = notificationDto.toNotificationEntity(it) - notificationObjects.add( - notificationsRepository.save(notification) - ) - } - } - - // Dispatch event - applicationEventPublisher.publishEvent( - NotificationUserPushEvent(notificationObjects) - ) - } - - fun getNotificationsNotDone(user: UserAccount, pageable: Pageable): Collection { - return notificationsRepository.findAllByMarkedDoneAtNullAndRecipient(user, pageable) - } - - fun getNotificationsDone(user: UserAccount, pageable: Pageable): Collection { - return notificationsRepository.findAllByMarkedDoneAtNotNullAndRecipient(user, pageable) - } - - fun getUnreadNotificationsCount(user: UserAccount): Int { - return notificationsRepository.countNotificationsByRecipientAndUnreadTrue(user) - } - - fun markAsRead(user: UserAccount, notifications: Set) { - return notificationsRepository.markAllAsRead(user) - } - - fun markAllAsRead(user: UserAccount) { - return notificationsRepository.markAllAsRead(user) - } - - fun markAsDone(user: UserAccount, notifications: Set) { - return notificationsRepository.markAllAsDone(user) - } - - fun markAllAsDone(user: UserAccount) { - return notificationsRepository.markAllAsDone(user) - } - - companion object { - val debouncedNotificationTypes: EnumSet = - EnumSet.of(Notification.NotificationType.ACTIVITY) - } -} diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationType.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationType.kt new file mode 100644 index 0000000000..a06ef0245e --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationType.kt @@ -0,0 +1,56 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.notifications + +import java.util.* + +enum class NotificationType { + ACTIVITY_LANGUAGES_CREATED, + ACTIVITY_KEYS_CREATED, + ACTIVITY_KEYS_UPDATED, + ACTIVITY_KEYS_SCREENSHOTS_UPLOADED, + ACTIVITY_TRANSLATIONS_UPDATED, + ACTIVITY_TRANSLATIONS_DELETED, + ACTIVITY_MARKED_AS_OUTDATED, + ACTIVITY_MARKED_AS_REVIEWED, + ACTIVITY_MARKED_AS_UNREVIEWED, + ACTIVITY_NEW_COMMENTS, + ACTIVITY_COMMENTS_MENTION, + + BATCH_JOB_ERRORED, + ; + + companion object { + val ACTIVITY_NOTIFICATIONS: EnumSet = EnumSet.of( + ACTIVITY_LANGUAGES_CREATED, + ACTIVITY_KEYS_CREATED, + ACTIVITY_KEYS_UPDATED, + ACTIVITY_KEYS_SCREENSHOTS_UPLOADED, + ACTIVITY_TRANSLATIONS_UPDATED, + ACTIVITY_TRANSLATIONS_DELETED, + ACTIVITY_MARKED_AS_OUTDATED, + ACTIVITY_MARKED_AS_REVIEWED, + ACTIVITY_MARKED_AS_UNREVIEWED, + ACTIVITY_NEW_COMMENTS, + ACTIVITY_COMMENTS_MENTION, + ) + + val BATCH_JOB_NOTIFICATIONS: EnumSet = EnumSet.of( + BATCH_JOB_ERRORED, + ) + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationDebouncer.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationDebouncer.kt new file mode 100644 index 0000000000..6d1b3c27c6 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationDebouncer.kt @@ -0,0 +1,117 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.notifications + +import io.tolgee.model.UserAccount +import io.tolgee.model.UserNotification +import io.tolgee.model.translation.TranslationComment +import io.tolgee.notifications.dto.NotificationCreateDto +import io.tolgee.notifications.dto.UserNotificationParamsDto +import io.tolgee.repository.UserNotificationRepository +import org.springframework.stereotype.Component +import java.util.* + +typealias UserNotificationDebounceResult = Pair, List> + +/** + * Component responsible for debouncing notifications based on existing notifications for a given user. + */ +@Component +class UserNotificationDebouncer( + private val userNotificationRepository: UserNotificationRepository +) { + /** + * Updates existing notifications when possible according to the debouncing policy. + * + * @return A pair of the notifications which have been updated, and the remaining notifications to process. + */ + fun debounce( + notificationDto: NotificationCreateDto, + params: List + ): UserNotificationDebounceResult { + if (NotificationType.ACTIVITY_NOTIFICATIONS.contains(notificationDto.type)) { + return debounceActivityNotification(notificationDto, params) + } + + return Pair(emptyList(), params) + } + + // -- + // Activity-related notifications + // -- + private fun debounceActivityNotification( + notificationDto: NotificationCreateDto, + params: List, + ): UserNotificationDebounceResult { + val debouncedUserNotifications = mutableListOf() + val notificationsToProcess = mutableListOf() + val notifications = fetchRelevantActivityNotifications(notificationDto, params.map { it.recipient }) + + params.forEach { + if (notifications.containsKey(it.recipient.id)) { + val notification = notifications[it.recipient.id]!! + notificationDto.mergeIntoUserNotificationEntity(notification, it) + debouncedUserNotifications.add(notification) + } else { + notificationsToProcess.add(it) + } + } + + return Pair(debouncedUserNotifications, notificationsToProcess) + } + + private fun fetchRelevantActivityNotifications( + notificationDto: NotificationCreateDto, + recipients: List, + ): Map { + if (commentNotificationTypes.contains(notificationDto.type)) + return fetchRelevantCommentActivityNotifications(notificationDto, recipients) + + val notifications = userNotificationRepository.findCandidatesForNotificationDebouncing( + notificationDto.type, + notificationDto.project, + recipients, + ) + + return notifications.associateBy { it.recipient.id } + } + + private fun fetchRelevantCommentActivityNotifications( + notificationDto: NotificationCreateDto, + recipients: List, + ): Map { + val translationId = notificationDto.modifiedEntities + ?.find { it.entityClass == TranslationComment::class.simpleName } + ?.describingRelations?.get("translation")?.entityId + ?: return emptyMap() + + val notifications = userNotificationRepository.findCandidatesForCommentNotificationDebouncing( + notificationDto.project, + recipients, + translationId, + ) + + return notifications.associateBy { it.recipient.id } + } + + companion object { + val commentNotificationTypes: EnumSet = EnumSet.of( + NotificationType.ACTIVITY_NEW_COMMENTS, + NotificationType.ACTIVITY_COMMENTS_MENTION, + ) + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt new file mode 100644 index 0000000000..0f16213104 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt @@ -0,0 +1,90 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.notifications + +import io.tolgee.model.UserAccount +import io.tolgee.model.UserNotification +import io.tolgee.notifications.dto.NotificationCreateDto +import io.tolgee.notifications.dto.UserNotificationParamsDto +import io.tolgee.notifications.events.UserNotificationPushEvent +import io.tolgee.repository.UserNotificationRepository +import org.springframework.context.ApplicationEventPublisher +import org.springframework.data.domain.Pageable +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional + +@Service +class UserNotificationService( + private val userNotificationRepository: UserNotificationRepository, + private val applicationEventPublisher: ApplicationEventPublisher, + private val userNotificationDebouncer: UserNotificationDebouncer, +) { + @Transactional + fun dispatchNotification(notificationDto: NotificationCreateDto, params: UserNotificationParamsDto) { + return dispatchNotifications(notificationDto, listOf(params)) + } + + @Transactional + fun dispatchNotifications(notificationDto: NotificationCreateDto, params: List) { + val userNotificationObjects = mutableSetOf() + + val (processed, remaining) = userNotificationDebouncer.debounce(notificationDto, params) + userNotificationObjects.addAll( + userNotificationRepository.saveAll(processed) + ) + + remaining.forEach { + val notification = notificationDto.toUserNotificationEntity(it) + userNotificationObjects.add( + userNotificationRepository.save(notification) + ) + } + + // Dispatch event + applicationEventPublisher.publishEvent( + UserNotificationPushEvent(userNotificationObjects) + ) + } + + fun getNotificationsNotDone(user: UserAccount, pageable: Pageable): Collection { + return userNotificationRepository.findAllByMarkedDoneAtNullAndRecipient(user, pageable) + } + + fun getNotificationsDone(user: UserAccount, pageable: Pageable): Collection { + return userNotificationRepository.findAllByMarkedDoneAtNotNullAndRecipient(user, pageable) + } + + fun getUnreadNotificationsCount(user: UserAccount): Int { + return userNotificationRepository.countNotificationsByRecipientAndUnreadTrue(user) + } + + fun markAsRead(user: UserAccount, notifications: Set) { + return userNotificationRepository.markAllAsRead(user) + } + + fun markAllAsRead(user: UserAccount) { + return userNotificationRepository.markAllAsRead(user) + } + + fun markAsDone(user: UserAccount, notifications: Set) { + return userNotificationRepository.markAllAsDone(user) + } + + fun markAllAsDone(user: UserAccount) { + return userNotificationRepository.markAllAsDone(user) + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt index 84643b87d5..d13f257504 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt @@ -16,14 +16,15 @@ package io.tolgee.notifications.dispatchers -import io.tolgee.activity.data.ActivityType +import io.tolgee.model.Screenshot import io.tolgee.model.UserAccount -import io.tolgee.model.batch.BatchJobStatus +import io.tolgee.model.activity.ActivityModifiedEntity import io.tolgee.model.enums.Scope -import io.tolgee.model.key.Key import io.tolgee.model.translation.Translation -import io.tolgee.notifications.NotificationService -import io.tolgee.notifications.dto.NotificationDispatchParamsDto +import io.tolgee.model.views.UserAccountProjectNotificationDataView +import io.tolgee.notifications.NotificationType +import io.tolgee.notifications.UserNotificationService +import io.tolgee.notifications.dto.UserNotificationParamsDto import io.tolgee.notifications.events.NotificationCreateEvent import io.tolgee.service.LanguageService import io.tolgee.service.security.PermissionService @@ -40,7 +41,7 @@ class UserNotificationDispatch( private val userAccountService: UserAccountService, private val permissionService: PermissionService, private val languageService: LanguageService, - private val notificationService: NotificationService, + private val userNotificationService: UserNotificationService, private val entityManager: EntityManager, ) : Logging { @Async @@ -49,182 +50,98 @@ class UserNotificationDispatch( logger.trace("Received notification creation event {}", e) when { - e.notification.activityRevision != null -> handleActivityNotification(e) - e.notification.batchJob != null -> handleBatchJobNotification(e) - else -> logger.warn("Encountered invalid notification create event {}", e) + NotificationType.ACTIVITY_NOTIFICATIONS.contains(e.notification.type) -> + handleActivityNotification(e) + NotificationType.BATCH_JOB_NOTIFICATIONS.contains(e.notification.type) -> + handleBatchJobNotification(e) + else -> + throw IllegalStateException("Encountered invalid notification type ${e.notification.type}") } } private fun handleActivityNotification(e: NotificationCreateEvent) { - when (e.notification.activityRevision!!.type) { - ActivityType.CREATE_LANGUAGE, - ActivityType.KEY_TAGS_EDIT, - ActivityType.KEY_NAME_EDIT, - ActivityType.CREATE_KEY, - ActivityType.NAMESPACE_EDIT, - ActivityType.BATCH_TAG_KEYS, - ActivityType.BATCH_UNTAG_KEYS, - ActivityType.BATCH_SET_KEYS_NAMESPACE, - ActivityType.COMPLEX_EDIT -> - handleGenericActivityNotification(e) - - ActivityType.SCREENSHOT_ADD -> - handleScreenshotActivityNotification(e) - - ActivityType.SET_TRANSLATION_STATE, - ActivityType.SET_TRANSLATIONS, - ActivityType.DISMISS_AUTO_TRANSLATED_STATE, - ActivityType.SET_OUTDATED_FLAG, - ActivityType.TRANSLATION_COMMENT_ADD, - ActivityType.TRANSLATION_COMMENT_EDIT, - ActivityType.TRANSLATION_COMMENT_SET_STATE, - ActivityType.BATCH_PRE_TRANSLATE_BY_TM, - ActivityType.BATCH_MACHINE_TRANSLATE, - ActivityType.AUTO_TRANSLATE, - ActivityType.BATCH_CLEAR_TRANSLATIONS, - ActivityType.BATCH_COPY_TRANSLATIONS, - ActivityType.BATCH_SET_TRANSLATION_STATE -> - handleTranslationActivityNotification(e) - - ActivityType.IMPORT -> - handleImportActivityNotification(e) - - // Do not show a notification about those type of events - // Intentionally not done as an else block to make this not compile if new activities are added - ActivityType.EDIT_PROJECT, - ActivityType.EDIT_LANGUAGE, - ActivityType.DELETE_LANGUAGE, - ActivityType.KEY_DELETE, - ActivityType.TRANSLATION_COMMENT_DELETE, - ActivityType.SCREENSHOT_DELETE, - ActivityType.CREATE_PROJECT, - ActivityType.UNKNOWN, - null -> {} + val users = userAccountService.getAllPermissionInformationOfPermittedUsersInProject(e.notification.project.id) + val translationToLanguageMap = e.notification.modifiedEntities!! + .filter { it.entityClass == Translation::class.simpleName } + .map { it.entityId } + .let { if (it.isEmpty()) emptyMap() else languageService.findLanguageIdsOfTranslations(it) } + + val notifications = users.mapNotNull { + if (it.id != e.responsibleUser?.id) + handleActivityNotificationForUser(e, translationToLanguageMap, it) + else + null } + + userNotificationService.dispatchNotifications(e.notification, notifications) } private fun handleBatchJobNotification(e: NotificationCreateEvent) { // Only send a full notification for job failures. - if (e.notification.meta["status"] != BatchJobStatus.FAILED) return + if (e.notification.type != NotificationType.BATCH_JOB_ERRORED) return val batchJob = e.notification.batchJob!! val author = batchJob.author ?: return - notificationService.dispatchNotification( + userNotificationService.dispatchNotification( e.notification, - NotificationDispatchParamsDto(author) + UserNotificationParamsDto(author) ) } - private fun handleGenericActivityNotification(e: NotificationCreateEvent) { - val revision = e.notification.activityRevision!! - val users = userAccountService.getAllPermissionInformationOfPermittedUsersInProject(revision.projectId!!) - - val dispatches = users - .filter { it.id != e.responsibleUser?.id } - .map { - NotificationDispatchParamsDto( - recipient = entityManager.getReference(UserAccount::class.java, it.id), - activityModifiedEntities = revision.modifiedEntities, - ) - } - - notificationService.dispatchNotifications(e.notification, dispatches) - } + private fun handleActivityNotificationForUser( + e: NotificationCreateEvent, + translationToLanguageMap: Map, + userPermissionData: UserAccountProjectNotificationDataView, + ): UserNotificationParamsDto? { + val permissions = permissionService.computeProjectPermission(userPermissionData).expandedScopes + + // Filter the entities the user is allowed to see + val filteredModifiedEntities = filterModifiedEntities( + e.notification.modifiedEntities!!, + permissions, + userPermissionData.permittedViewLanguages, + translationToLanguageMap, + ) - private fun handleScreenshotActivityNotification(e: NotificationCreateEvent) { - val revision = e.notification.activityRevision!! - val users = userAccountService.getAllPermissionInformationOfPermittedUsersInProject(revision.projectId!!) + if (filteredModifiedEntities.isEmpty()) return null - val dispatches = users - .filter { - if (it.id == e.responsibleUser?.id) return@filter false - val computedPermissions = permissionService.computeProjectPermission(it) - computedPermissions.expandedScopes.contains(Scope.SCREENSHOTS_VIEW) - } - .map { - NotificationDispatchParamsDto( - recipient = entityManager.getReference(UserAccount::class.java, it.id), - activityModifiedEntities = revision.modifiedEntities, - ) - } - - notificationService.dispatchNotifications(e.notification, dispatches) + return UserNotificationParamsDto( + recipient = entityManager.getReference(UserAccount::class.java, userPermissionData.id), + modifiedEntities = filteredModifiedEntities.toSet(), + ) } - private fun handleTranslationActivityNotification(e: NotificationCreateEvent) { - val revision = e.notification.activityRevision!! - val users = userAccountService.getAllPermissionInformationOfPermittedUsersInProject(revision.projectId!!) - - val translationEntities = revision.modifiedEntities - .filter { it.entityClass == Translation::class.simpleName } - - val translationIds = translationEntities.map { it.entityId } - val translationToLangMap = languageService.findLanguageIdsOfTranslations(translationIds) - - val dispatches = users + private fun filterModifiedEntities( + modifiedEntities: List, + permissions: Array, + permittedViewLanguages: List?, + translationToLanguageMap: Map, + ): Set { + return modifiedEntities .filter { - if (it.id == e.responsibleUser?.id) return@filter false - val computedPermissions = permissionService.computeProjectPermission(it) - computedPermissions.expandedScopes.contains(Scope.TRANSLATIONS_VIEW) - } - .map { - val visibleModifiedEntities = translationEntities.filter { entity -> - val languageId = translationToLangMap[entity.entityId] ?: return@filter false - it.permittedViewLanguages?.contains(languageId) != false + when (it.entityClass) { + Screenshot::class.simpleName -> + isUserAllowedToSeeScreenshot(permissions) + Translation::class.simpleName -> + isUserAllowedToSeeTranslation(it, permissions, permittedViewLanguages, translationToLanguageMap) + else -> true } - - NotificationDispatchParamsDto( - recipient = entityManager.getReference(UserAccount::class.java, it.id), - activityModifiedEntities = visibleModifiedEntities, - ) - } - .filter { - it.activityModifiedEntities.isNotEmpty() - } - - notificationService.dispatchNotifications(e.notification, dispatches) + }.toSet() } - private fun handleImportActivityNotification(e: NotificationCreateEvent) { - val revision = e.notification.activityRevision!! - - val keysCount = revision.modifiedEntities.count { it.entityClass == Key::class.simpleName } - - // Count translations per locale - val translationIds = revision.modifiedEntities - .filter { it.entityClass == Translation::class.simpleName } - .map { it.entityId } - - val translationToLangMap = languageService.findLanguageIdsOfTranslations(translationIds) - - val importedTranslationsPerLocale = mutableMapOf() - translationToLangMap.values.forEach { - importedTranslationsPerLocale.merge(it, 1) { a, b -> a + b } - } - - // Filter users - val users = userAccountService.getAllPermissionInformationOfPermittedUsersInProject(revision.projectId!!) + private fun isUserAllowedToSeeScreenshot(permissions: Array): Boolean { + return permissions.contains(Scope.SCREENSHOTS_VIEW) + } - val dispatches = users - .filter { - if (it.id == e.responsibleUser?.id) return@filter false - val computedPermissions = permissionService.computeProjectPermission(it) - computedPermissions.expandedScopes.contains(Scope.TRANSLATIONS_VIEW) - } - .map { - val userVisibleTranslationCount = importedTranslationsPerLocale - .filterKeys { l -> it.permittedViewLanguages?.contains(l) != false } - .values.reduce { acc, i -> acc + i } - - NotificationDispatchParamsDto( - recipient = entityManager.getReference(UserAccount::class.java, it.id), - meta = mutableMapOf("keysCount" to keysCount, "translationsCount" to userVisibleTranslationCount) - ) - } - .filter { - it.meta["translationsCount"] != 0 - } + private fun isUserAllowedToSeeTranslation( + entity: ActivityModifiedEntity, + permissions: Array, + permittedViewLanguages: List?, + translationToLanguageMap: Map, + ): Boolean { + if (!permissions.contains(Scope.TRANSLATIONS_VIEW)) return false - notificationService.dispatchNotifications(e.notification, dispatches) + val language = translationToLanguageMap[entity.entityId] ?: return false + return permittedViewLanguages?.contains(language) != false } } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt index bec1728368..da5b898dcb 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt @@ -16,85 +16,41 @@ package io.tolgee.notifications.dto -import io.tolgee.model.Notification import io.tolgee.model.Project -import io.tolgee.model.activity.ActivityRevision +import io.tolgee.model.UserNotification +import io.tolgee.model.activity.ActivityModifiedEntity import io.tolgee.model.batch.BatchJob +import io.tolgee.notifications.NotificationType data class NotificationCreateDto( + val type: NotificationType, val project: Project, - val activityRevision: ActivityRevision? = null, - val batchJob: BatchJob? = null, - val meta: MutableMap = mutableMapOf(), + val modifiedEntities: MutableList? = null, + val batchJob: BatchJob? = null ) { - val type = when { - activityRevision != null -> Notification.NotificationType.ACTIVITY - batchJob != null -> Notification.NotificationType.BATCH_JOB_FAILURE - else -> throw IllegalStateException("No entity attached to this DTO!") - } - - constructor(project: Project, activityRevision: ActivityRevision) : - this(project, activityRevision = activityRevision, batchJob = null) - - constructor(project: Project, batchJob: BatchJob) : - this(project, activityRevision = null, batchJob = batchJob) - - init { - if (activityRevision == null && batchJob == null) { - throw IllegalArgumentException("No entity attached to the notification") - } - - if (activityRevision != null && batchJob != null) { - throw IllegalArgumentException("Too many entities attached to the notification") - } - } - - fun toNotificationEntity(params: NotificationDispatchParamsDto): Notification { - val mergedMeta = meta.toMutableMap() - mergedMeta.putAll(params.meta) - - return Notification( + fun toUserNotificationEntity(params: UserNotificationParamsDto): UserNotification { + return UserNotification( type = type, recipient = params.recipient, project = project, - activityRevisions = activityRevision?.let { mutableSetOf(activityRevision) } ?: mutableSetOf(), - activityModifiedEntities = params.activityModifiedEntities.toMutableSet(), - meta = mergedMeta, + modifiedEntities = params.modifiedEntities.toMutableSet() ) } - fun mergeIntoNotificationEntity(notification: Notification, params: NotificationDispatchParamsDto) { - when (notification.type) { - Notification.NotificationType.ACTIVITY -> - mergeIntoNotificationEntityActivity(notification, params) + fun mergeIntoUserNotificationEntity(userNotification: UserNotification, params: UserNotificationParamsDto) { + when { + NotificationType.ACTIVITY_NOTIFICATIONS.contains(userNotification.type) -> + mergeIntoNotificationEntityActivity(userNotification, params) - Notification.NotificationType.BATCH_JOB_FAILURE -> - throw IllegalArgumentException("Cannot merge notifications of type ${notification.type}") + else -> + throw IllegalArgumentException("Cannot merge notifications of type ${userNotification.type}") } } - private fun mergeIntoNotificationEntityActivity(notification: Notification, params: NotificationDispatchParamsDto) { - if (activityRevision == null) - throw IllegalArgumentException("Tried to merge notifications of incompatible type") - if (notification.recipient.id != params.recipient.id) - throw IllegalArgumentException( - "Tried to merge a notification for user#${notification.recipient.id}, " + - "but specified ${params.recipient.id} as recipient in notification dispatch parameters" - ) - - notification.activityRevisions.add(activityRevision) - params.activityModifiedEntities.forEach { - val existing = notification.activityModifiedEntities.find { ex -> - ex.activityRevision.id == it.activityRevision.id && - ex.entityId == it.entityId && - ex.entityClass == it.entityClass - } - - if (existing == null) { - notification.activityModifiedEntities.add(it) - } - } - - notification.meta.putAll(params.meta) + private fun mergeIntoNotificationEntityActivity( + userNotification: UserNotification, + params: UserNotificationParamsDto, + ) { + userNotification.modifiedEntities.addAll(params.modifiedEntities) } } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationDispatchParamsDto.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/UserNotificationParamsDto.kt similarity index 81% rename from backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationDispatchParamsDto.kt rename to backend/data/src/main/kotlin/io/tolgee/notifications/dto/UserNotificationParamsDto.kt index faebba87cb..e97299f3db 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationDispatchParamsDto.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/UserNotificationParamsDto.kt @@ -19,8 +19,7 @@ package io.tolgee.notifications.dto import io.tolgee.model.UserAccount import io.tolgee.model.activity.ActivityModifiedEntity -data class NotificationDispatchParamsDto( +data class UserNotificationParamsDto( val recipient: UserAccount, - val activityModifiedEntities: List = emptyList(), - val meta: MutableMap = mutableMapOf(), + val modifiedEntities: Set = emptySet() ) diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationCreateEvent.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationCreateEvent.kt index c7fa2a7363..4550ada6fc 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationCreateEvent.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationCreateEvent.kt @@ -19,7 +19,7 @@ package io.tolgee.notifications.events import io.tolgee.model.UserAccount import io.tolgee.notifications.dto.NotificationCreateDto -data class NotificationCreateEvent( +class NotificationCreateEvent( val notification: NotificationCreateDto, val responsibleUser: UserAccount?, val source: Any? = null diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationUserPushEvent.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/events/UserNotificationPushEvent.kt similarity index 86% rename from backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationUserPushEvent.kt rename to backend/data/src/main/kotlin/io/tolgee/notifications/events/UserNotificationPushEvent.kt index 041bcf5988..d1052e802e 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationUserPushEvent.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/events/UserNotificationPushEvent.kt @@ -16,9 +16,9 @@ package io.tolgee.notifications.events -import io.tolgee.model.Notification +import io.tolgee.model.UserNotification /** * Event sent when a set of users received a new notification. */ -data class NotificationUserPushEvent(val notifications: Set) +data class UserNotificationPushEvent(val notifications: Set) diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt index 5a43db091f..52af0a7e30 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt @@ -16,9 +16,18 @@ package io.tolgee.notifications.listeners +import io.tolgee.activity.data.ActivityType +import io.tolgee.activity.data.RevisionType import io.tolgee.events.OnProjectActivityStoredEvent import io.tolgee.model.Project +import io.tolgee.model.Screenshot import io.tolgee.model.UserAccount +import io.tolgee.model.activity.ActivityModifiedEntity +import io.tolgee.model.enums.TranslationState +import io.tolgee.model.key.Key +import io.tolgee.model.key.KeyMeta +import io.tolgee.model.translation.Translation +import io.tolgee.notifications.NotificationType import io.tolgee.notifications.dto.NotificationCreateDto import io.tolgee.notifications.events.NotificationCreateEvent import io.tolgee.util.Logging @@ -28,6 +37,8 @@ import org.springframework.context.event.EventListener import org.springframework.stereotype.Component import javax.persistence.EntityManager +private typealias SortedTranslations = List>> + @Component class ActivityEventListener( private val applicationEventPublisher: ApplicationEventPublisher, @@ -50,17 +61,233 @@ class ActivityEventListener( entityManager.getReference(UserAccount::class.java, it) } - val notificationDto = NotificationCreateDto( - project = project, - activityRevision = e.activityRevision - ) + when (e.activityRevision.type) { + // ACTIVITY_LANGUAGES_CREATED + ActivityType.CREATE_LANGUAGE -> + processSimpleActivity(NotificationType.ACTIVITY_LANGUAGES_CREATED, project, responsibleUser, e) + + // ACTIVITY_KEYS_CREATED + ActivityType.CREATE_KEY -> + processSimpleActivity(NotificationType.ACTIVITY_KEYS_CREATED, project, responsibleUser, e) + + // ACTIVITY_KEYS_UPDATED + ActivityType.KEY_TAGS_EDIT, + ActivityType.KEY_NAME_EDIT, + ActivityType.BATCH_TAG_KEYS, + ActivityType.BATCH_UNTAG_KEYS, + ActivityType.BATCH_SET_KEYS_NAMESPACE -> + processSimpleActivity(NotificationType.ACTIVITY_KEYS_UPDATED, project, responsibleUser, e) + + // ACTIVITY_KEYS_UPDATED, ACTIVITY_KEYS_SCREENSHOTS_UPLOADED, ACTIVITY_TRANSLATIONS_* + ActivityType.COMPLEX_EDIT -> + processComplexEdit(project, responsibleUser, e) + + // ACTIVITY_KEYS_SCREENSHOTS_UPLOADED + ActivityType.SCREENSHOT_ADD -> + processScreenshotUpdate(project, responsibleUser, e) + + // ACTIVITY_TRANSLATIONS_*, ACTIVITY_MARKED_AS_OUTDATED, ACTIVITY_MARKED_AS_(UN)REVIEWED + ActivityType.SET_TRANSLATIONS, + ActivityType.SET_TRANSLATION_STATE, + ActivityType.SET_OUTDATED_FLAG, + ActivityType.BATCH_PRE_TRANSLATE_BY_TM, + ActivityType.BATCH_MACHINE_TRANSLATE, + ActivityType.AUTO_TRANSLATE, + ActivityType.BATCH_CLEAR_TRANSLATIONS, + ActivityType.BATCH_COPY_TRANSLATIONS, + ActivityType.BATCH_SET_TRANSLATION_STATE -> + processSetTranslations(project, responsibleUser, e) + + // ACTIVITY_NEW_COMMENTS (ACTIVITY_COMMENTS_MENTION is user-specific and not computed here) + ActivityType.TRANSLATION_COMMENT_ADD -> + processSimpleActivity(NotificationType.ACTIVITY_NEW_COMMENTS, project, responsibleUser, e) + + // ACTIVITY_DATA_IMPORTED + ActivityType.IMPORT -> + processImport(project, responsibleUser, e) + + // We don't care about those, ignore them. + // They're explicitly not written as a single `else` branch, + // so it causes a compile error when new activities are added + // and ensures the notification policy is adjusted accordingly. + ActivityType.UNKNOWN, + ActivityType.DISMISS_AUTO_TRANSLATED_STATE, + ActivityType.TRANSLATION_COMMENT_DELETE, + ActivityType.TRANSLATION_COMMENT_EDIT, + ActivityType.TRANSLATION_COMMENT_SET_STATE, + ActivityType.SCREENSHOT_DELETE, + ActivityType.KEY_DELETE, + ActivityType.EDIT_LANGUAGE, + ActivityType.DELETE_LANGUAGE, + ActivityType.CREATE_PROJECT, + ActivityType.EDIT_PROJECT, + ActivityType.NAMESPACE_EDIT, + ActivityType.AUTOMATION, + null -> {} + } + } + /** + * Handles activities that can be simply mapped to a corresponding notification without extra processing. + */ + private fun processSimpleActivity( + type: NotificationType, + project: Project, + responsibleUser: UserAccount?, + e: OnProjectActivityStoredEvent, + ) { applicationEventPublisher.publishEvent( NotificationCreateEvent( - notificationDto, + NotificationCreateDto(type, project, e.activityRevision.modifiedEntities), responsibleUser, source = e, ) ) } + + /** + * Emits multiple notification create events depending on the details of the complex edition. + */ + private fun processComplexEdit( + project: Project, + responsibleUser: UserAccount?, + e: OnProjectActivityStoredEvent, + ) { + processComplexEditKeyUpdate(project, responsibleUser, e) + processScreenshotUpdate(project, responsibleUser, e) + processSetTranslations(project, responsibleUser, e) + } + + private fun processComplexEditKeyUpdate( + project: Project, + responsibleUser: UserAccount?, + e: OnProjectActivityStoredEvent, + ) { + // The key was updated if: + // The entity is a Key and its name or namespace was modified; + // The entity is a KeyMeta and its tags were modified. + val relevantEntities = e.activityRevision.modifiedEntities.filter { + ( + it.entityClass == Key::class.simpleName && + (it.modifications.containsKey("name") || it.modifications.containsKey("namespace")) + ) || + ( + it.entityClass == KeyMeta::class.simpleName && + it.modifications.containsKey("tags") + ) + } + + if (relevantEntities.isNotEmpty()) { + applicationEventPublisher.publishEvent( + NotificationCreateEvent( + NotificationCreateDto(NotificationType.ACTIVITY_KEYS_UPDATED, project, relevantEntities.toMutableList()), + responsibleUser, + source = e, + ) + ) + } + } + + /** + * Emits notifications based on whether a translation was added, updated or removed. + * + * Refer to the Hacking Documentation, Notifications, Activity Notifications - User Dispatch, §2.2.2. + */ + private fun processSetTranslations( + project: Project, + responsibleUser: UserAccount?, + e: OnProjectActivityStoredEvent, + ) { + val sortedTranslations = sortTranslations(e.activityRevision.modifiedEntities) + for ((type, translations) in sortedTranslations) { + if (translations.isNotEmpty()) { + applicationEventPublisher.publishEvent( + NotificationCreateEvent( + NotificationCreateDto(type, project, translations), + responsibleUser, + source = e, + ) + ) + } + } + } + + private fun sortTranslations(entities: List): SortedTranslations { + val updatedTranslations = mutableListOf() + val deletedTranslations = mutableListOf() + val outdatedTranslations = mutableListOf() + val reviewedTranslations = mutableListOf() + val unreviewedTranslations = mutableListOf() + + entities.forEach { + if (it.entityClass != Translation::class.simpleName) return@forEach + + val text = it.modifications["text"] + val state = it.modifications["state"] + val outdated = it.modifications["outdated"] + + if (text != null) { + if (text.new == null) deletedTranslations.add(it) + else updatedTranslations.add(it) + } + + if (outdated?.new == true) outdatedTranslations.add(it) + if (state?.new == TranslationState.REVIEWED.name) outdatedTranslations.add(it) + if (state?.new == TranslationState.TRANSLATED.name && state.old == TranslationState.REVIEWED.name) + unreviewedTranslations.add(it) + } + + return listOf( + Pair(NotificationType.ACTIVITY_TRANSLATIONS_UPDATED, updatedTranslations), + Pair(NotificationType.ACTIVITY_TRANSLATIONS_DELETED, deletedTranslations), + Pair(NotificationType.ACTIVITY_MARKED_AS_OUTDATED, outdatedTranslations), + Pair(NotificationType.ACTIVITY_MARKED_AS_REVIEWED, reviewedTranslations), + Pair(NotificationType.ACTIVITY_MARKED_AS_UNREVIEWED, unreviewedTranslations), + ) + } + + private fun processScreenshotUpdate( + project: Project, + responsibleUser: UserAccount?, + e: OnProjectActivityStoredEvent, + ) { + val addedScreenshots = e.activityRevision.modifiedEntities + .filter { it.entityClass == Screenshot::class.simpleName && it.revisionType == RevisionType.ADD } + + if (addedScreenshots.isNotEmpty()) { + applicationEventPublisher.publishEvent( + NotificationCreateEvent( + NotificationCreateDto( + type = NotificationType.ACTIVITY_KEYS_SCREENSHOTS_UPLOADED, + project = project, + modifiedEntities = addedScreenshots.toMutableList() + ), + responsibleUser, + source = e, + ) + ) + } + } + + private fun processImport( + project: Project, + responsibleUser: UserAccount?, + e: OnProjectActivityStoredEvent, + ) { + val createdKeys = e.activityRevision.modifiedEntities + .filter { it.entityClass == Key::class.simpleName && it.revisionType == RevisionType.ADD } + + if (createdKeys.isNotEmpty()) { + println("new keys") + applicationEventPublisher.publishEvent( + NotificationCreateEvent( + NotificationCreateDto(NotificationType.ACTIVITY_KEYS_CREATED, project, createdKeys.toMutableList()), + responsibleUser, + source = e, + ) + ) + } + + processSetTranslations(project, responsibleUser, e) + } } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt index a33a730c0f..b274e73376 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt @@ -16,11 +16,10 @@ package io.tolgee.notifications.listeners -import io.tolgee.batch.BatchJobService -import io.tolgee.batch.data.BatchJobDto -import io.tolgee.batch.events.* +import io.tolgee.batch.events.OnBatchJobFailed +import io.tolgee.model.Project import io.tolgee.model.batch.BatchJob -import io.tolgee.model.batch.BatchJobStatus +import io.tolgee.notifications.NotificationType import io.tolgee.notifications.dto.NotificationCreateDto import io.tolgee.notifications.events.NotificationCreateEvent import io.tolgee.util.Logging @@ -28,83 +27,13 @@ import io.tolgee.util.logger import org.springframework.context.ApplicationEventPublisher import org.springframework.context.event.EventListener import org.springframework.stereotype.Component +import javax.persistence.EntityManager @Component class BatchJobListener( private val applicationEventPublisher: ApplicationEventPublisher, - private val batchJobService: BatchJobService, + private val entityManager: EntityManager, ) : Logging { - @EventListener - fun onBatchEventQueued(e: OnBatchJobCreated) { - logger.trace( - "Received batch job created event - job#{} on proj#{}", - e.job.id, - e.job.project.id, - ) - - val notification = createNotificationBase(e.job) - notification.meta["status"] = BatchJobStatus.PENDING - doDispatch(notification, e) - } - - @EventListener - fun onBatchEventStarted(e: OnBatchJobStarted) { - logger.trace( - "Received batch job started event - job#{} on proj#{}", - e.job.id, - e.job.projectId, - ) - - val notification = createNotificationBase(e.job) - notification.meta["status"] = BatchJobStatus.RUNNING - notification.meta["processed"] = 0 - notification.meta["total"] = e.job.totalChunks - doDispatch(notification, e) - } - - @EventListener - fun onBatchEventProgress(e: OnBatchJobProgress) { - logger.trace( - "Received batch job progress event - job#{} on proj#{} ({}/{})", - e.job.id, - e.job.projectId, - e.processed, - e.total, - ) - - val notification = createNotificationBase(e.job) - notification.meta["status"] = BatchJobStatus.RUNNING - notification.meta["processed"] = e.processed - notification.meta["total"] = e.total - doDispatch(notification, e) - } - - @EventListener - fun onBatchEventSuccess(e: OnBatchJobSucceeded) { - logger.trace( - "Received batch job success event - job#{} on proj#{}", - e.job.id, - e.job.projectId, - ) - - val notification = createNotificationBase(e.job) - notification.meta["status"] = BatchJobStatus.SUCCESS - doDispatch(notification, e) - } - - @EventListener - fun onBatchEventSuccess(e: OnBatchJobCancelled) { - logger.trace( - "Received batch job cancel event - job#{} on proj#{}", - e.job.id, - e.job.projectId, - ) - - val notification = createNotificationBase(e.job) - notification.meta["status"] = BatchJobStatus.CANCELLED - doDispatch(notification, e) - } - @EventListener fun onBatchJobError(e: OnBatchJobFailed) { logger.trace( @@ -113,30 +42,18 @@ class BatchJobListener( e.job.projectId, ) - val notification = createNotificationBase(e.job) - notification.meta["status"] = BatchJobStatus.FAILED - doDispatch(notification, e) - } - - private fun doDispatch(notification: NotificationCreateDto, source: Any) { + val job = entityManager.getReference(BatchJob::class.java, e.job.id) + val project = entityManager.getReference(Project::class.java, e.job.projectId) applicationEventPublisher.publishEvent( NotificationCreateEvent( - notification, - source = source, + NotificationCreateDto( + type = NotificationType.BATCH_JOB_ERRORED, + project = project, + batchJob = job, + ), + source = e, responsibleUser = null, ) ) } - - private fun createNotificationBase(batchJob: BatchJob): NotificationCreateDto { - return NotificationCreateDto( - project = batchJob.project, - batchJob = batchJob - ) - } - - private fun createNotificationBase(batchJobDto: BatchJobDto): NotificationCreateDto { - val job = batchJobService.getJobEntity(batchJobDto.id) - return createNotificationBase(job) - } } diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/NotificationsRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/NotificationsRepository.kt deleted file mode 100644 index fc730d332b..0000000000 --- a/backend/data/src/main/kotlin/io/tolgee/repository/NotificationsRepository.kt +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright (C) 2023 Tolgee s.r.o. and contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.tolgee.repository - -import io.tolgee.model.Notification -import io.tolgee.model.Project -import io.tolgee.model.UserAccount -import org.springframework.data.domain.Pageable -import org.springframework.data.jpa.repository.JpaRepository -import org.springframework.data.jpa.repository.Modifying -import org.springframework.data.jpa.repository.Query -import org.springframework.stereotype.Repository - -@Repository -interface NotificationsRepository : JpaRepository { - fun findAllByRecipient(recipient: UserAccount): List - - fun findAllByMarkedDoneAtNullAndRecipient(recipient: UserAccount, pageable: Pageable): List - - fun findAllByMarkedDoneAtNotNullAndRecipient(recipient: UserAccount, pageable: Pageable): List - - fun countNotificationsByRecipientAndUnreadTrue(recipient: UserAccount): Int - - @Query( - """ - SELECT new map(n.recipient.id, n) - FROM Notification n - WHERE - n.unread = true AND - n.type = :type AND - n.project = :project AND - n.recipient IN :recipients - """ - ) - fun findNotificationsToDebounceMappedByUser( - type: Notification.NotificationType, - project: Project, - recipients: Collection, - ): Map - - @Modifying - @Query("UPDATE Notification n SET n.unread = false WHERE n.recipient = ?1 AND n.id IN ?2") - fun markAsRead(recipient: UserAccount, notifications: Collection) - - @Modifying - @Query("UPDATE Notification n SET n.unread = false WHERE n.recipient = ?1") - fun markAllAsRead(recipient: UserAccount) - - @Modifying - @Query("UPDATE Notification n SET n.unread = true WHERE n.recipient = ?1 AND n.id IN ?2") - fun markAsUnread(recipient: UserAccount, notifications: Collection) - - @Modifying - @Query("UPDATE Notification n SET n.unread = true WHERE n.recipient = ?1") - fun markAllAsUnread(recipient: UserAccount) - - @Modifying - @Query("UPDATE Notification n SET n.unread = false, n.markedDoneAt = NOW() WHERE n.recipient = ?1 AND n.id IN ?2") - fun markAsDone(recipient: UserAccount, notifications: Collection) - - @Modifying - @Query("UPDATE Notification n SET n.unread = false, n.markedDoneAt = NOW() WHERE n.recipient = ?1") - fun markAllAsDone(recipient: UserAccount) - - @Modifying - @Query("UPDATE Notification n SET n.markedDoneAt = null WHERE n.recipient = ?1 AND n.id IN ?2") - fun unmarkAsDone(recipient: UserAccount, notifications: Collection) - - @Modifying - @Query("DELETE FROM notifications WHERE marked_done_at < NOW() - INTERVAL '90 DAY'", nativeQuery = true) - fun pruneOldNotifications() // Native query since HQL can't do "INTERVAL" -} diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt index 2da39c4572..a8c8ee7b5a 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt @@ -2,7 +2,7 @@ package io.tolgee.repository import io.tolgee.model.UserAccount import io.tolgee.model.views.UserAccountInProjectView -import io.tolgee.model.views.UserAccountProjectPermissionDataView +import io.tolgee.model.views.UserAccountProjectNotificationDataView import io.tolgee.model.views.UserAccountWithOrganizationRoleView import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable @@ -157,7 +157,7 @@ interface UserAccountRepository : JpaRepository { @Query( """ - SELECT new io.tolgee.model.views.UserAccountProjectPermissionDataView( + SELECT new io.tolgee.model.views.UserAccountProjectNotificationDataView( ua.id, p.id, org_r.type, @@ -188,5 +188,5 @@ interface UserAccountRepository : JpaRepository { GROUP BY ua.id, p.id, org_r.type, perm_org.type, perm_org._scopes, perm.type, perm._scopes """ ) - fun findAllPermittedUsersProjectPermissionView(projectId: Long): List + fun findAllPermittedUsersProjectPermissionView(projectId: Long): List } diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/UserNotificationRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/UserNotificationRepository.kt new file mode 100644 index 0000000000..3210114439 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/repository/UserNotificationRepository.kt @@ -0,0 +1,113 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.repository + +import io.tolgee.model.Project +import io.tolgee.model.UserAccount +import io.tolgee.model.UserNotification +import io.tolgee.notifications.NotificationType +import org.springframework.data.domain.Pageable +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Modifying +import org.springframework.data.jpa.repository.Query +import org.springframework.stereotype.Repository + +@Repository +interface UserNotificationRepository : JpaRepository { + fun findAllByRecipient(recipient: UserAccount): List + + fun findAllByMarkedDoneAtNullAndRecipient(recipient: UserAccount, pageable: Pageable): List + + fun findAllByMarkedDoneAtNotNullAndRecipient(recipient: UserAccount, pageable: Pageable): List + + fun countNotificationsByRecipientAndUnreadTrue(recipient: UserAccount): Int + + @Query( + """ + FROM UserNotification un + WHERE + un.unread = true AND + un.type = :type AND + un.project = :project AND + un.recipient IN :recipients + """ + ) + fun findCandidatesForNotificationDebouncing( + type: NotificationType, + project: Project, + recipients: Collection, + ): List + + @Modifying + @Query("UPDATE UserNotification un SET un.unread = false WHERE un.recipient = ?1 AND un.id IN ?2") + fun markAsRead(recipient: UserAccount, notifications: Collection) + + @Query( + """ + SELECT un + FROM UserNotification un + INNER JOIN un.modifiedEntities me + INNER JOIN ActivityDescribingEntity de ON de.activityRevision = me.activityRevision + WHERE + un.unread = true AND + un.type IN ( + io.tolgee.notifications.NotificationType.ACTIVITY_NEW_COMMENTS, + io.tolgee.notifications.NotificationType.ACTIVITY_COMMENTS_MENTION + ) AND + me.entityClass = 'TranslationComment' AND + de.entityClass = 'Translation' AND + de.entityId = :translationId AND + un.project = :project AND + un.recipient IN :recipients + """ + ) + fun findCandidatesForCommentNotificationDebouncing( + project: Project, + recipients: Collection, + translationId: Long, + ): List + + @Modifying + @Query("UPDATE UserNotification un SET un.unread = false WHERE un.recipient = ?1") + fun markAllAsRead(recipient: UserAccount) + + @Modifying + @Query("UPDATE UserNotification un SET un.unread = true WHERE un.recipient = ?1 AND un.id IN ?2") + fun markAsUnread(recipient: UserAccount, notifications: Collection) + + @Modifying + @Query("UPDATE UserNotification un SET un.unread = true WHERE un.recipient = ?1") + fun markAllAsUnread(recipient: UserAccount) + + @Modifying + @Query( + "UPDATE UserNotification un SET un.unread = false, un.markedDoneAt = NOW() WHERE un.recipient = ?1 AND un.id IN ?2" + ) + fun markAsDone(recipient: UserAccount, notifications: Collection) + + @Modifying + @Query("UPDATE UserNotification un SET un.unread = false, un.markedDoneAt = NOW() WHERE un.recipient = ?1") + fun markAllAsDone(recipient: UserAccount) + + @Modifying + @Query("UPDATE UserNotification un SET un.markedDoneAt = null WHERE un.recipient = ?1 AND un.id IN ?2") + fun unmarkAsDone(recipient: UserAccount, notifications: Collection) + + @Modifying + @Query("DELETE FROM user_notification WHERE marked_done_at < NOW() - INTERVAL '90 DAY'", nativeQuery = true) + fun pruneOldNotifications() // Native query since HQL can't do "INTERVAL" +} diff --git a/backend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.kt b/backend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.kt index 98162d9354..514a0ea5cc 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.kt @@ -21,7 +21,7 @@ import io.tolgee.model.UserAccount import io.tolgee.model.enums.OrganizationRoleType import io.tolgee.model.enums.ProjectPermissionType import io.tolgee.model.enums.Scope -import io.tolgee.model.views.UserAccountProjectPermissionDataView +import io.tolgee.model.views.UserAccountProjectNotificationDataView import io.tolgee.repository.PermissionRepository import io.tolgee.service.CachedPermissionService import io.tolgee.service.LanguageService @@ -189,7 +189,7 @@ class PermissionService( } fun computeProjectPermission( - projectPermissionDataView: UserAccountProjectPermissionDataView + projectPermissionDataView: UserAccountProjectNotificationDataView ): ComputedPermissionDto { val basePermissions = ComputedPermissionDto.getEmptyPermission( type = projectPermissionDataView.basePermissionsBasic, diff --git a/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt b/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt index b6340d3464..a1ab0bb51a 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt @@ -19,7 +19,7 @@ import io.tolgee.exceptions.PermissionException import io.tolgee.model.UserAccount import io.tolgee.model.views.ExtendedUserAccountInProject import io.tolgee.model.views.UserAccountInProjectView -import io.tolgee.model.views.UserAccountProjectPermissionDataView +import io.tolgee.model.views.UserAccountProjectNotificationDataView import io.tolgee.model.views.UserAccountWithOrganizationRoleView import io.tolgee.repository.UserAccountRepository import io.tolgee.service.AvatarService @@ -304,7 +304,7 @@ class UserAccountService( fun getAllPermissionInformationOfPermittedUsersInProject( projectId: Long - ): List { + ): List { return userAccountRepository.findAllPermittedUsersProjectPermissionView(projectId) } diff --git a/backend/data/src/main/resources/db/changelog/schema.xml b/backend/data/src/main/resources/db/changelog/schema.xml index 97180678d9..2de2f6ceb7 100644 --- a/backend/data/src/main/resources/db/changelog/schema.xml +++ b/backend/data/src/main/resources/db/changelog/schema.xml @@ -2955,17 +2955,16 @@ - + - - + + - + - @@ -2981,51 +2980,35 @@ - - - + + + - + - + - + - - - - - - - - - - - - - - - - - - + + - - + + - - + + - - + + - - + + diff --git a/backend/testing/src/main/kotlin/io/tolgee/fixtures/statusExpectations.kt b/backend/testing/src/main/kotlin/io/tolgee/fixtures/statusExpectations.kt index 39c82b6c29..eb6963b15a 100644 --- a/backend/testing/src/main/kotlin/io/tolgee/fixtures/statusExpectations.kt +++ b/backend/testing/src/main/kotlin/io/tolgee/fixtures/statusExpectations.kt @@ -80,12 +80,16 @@ fun ResultActions.tryPrettyPrinting(fn: ResultActions.() -> ResultActions): Resu val ResultActions.andGetContentAsString get() = this.andReturn().response.getContentAsString(StandardCharsets.UTF_8) +val ResultActions.andGetContentAsJsonMap + @Suppress("UNCHECKED_CAST") + get() = jacksonObjectMapper().readValue(andGetContentAsString, MutableMap::class.java) as MutableMap + val ResultActions.andAssertError get() = assertThat(this.andReturn()).error() val ResultActions.andPrettyPrint: ResultActions get() = jacksonObjectMapper().let { mapper -> - val parsed = mapper.readValue(this.andGetContentAsString) + val parsed = mapper.readValue(andGetContentAsString) println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(parsed)) return this } From 397dd088fe0570fead7978a60b7c193aba563615 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Sun, 3 Dec 2023 11:12:19 +0100 Subject: [PATCH 09/44] chore(deps): solve ij classpath issues with json-unit & assertj --- .../v2/controllers/V2UserControllerTest.kt | 2 +- .../ContentDeliveryConfigControllerTest.kt | 1 + .../OrganizationControllerInvitingTest.kt | 1 + .../OrganizationControllerTest.kt | 14 ++++++-- .../TranslationsControllerCursorTest.kt | 1 + .../TranslationsControllerModificationTest.kt | 1 + .../SecuredV2ImageUploadControllerTest.kt | 9 ++++-- .../V2ImageUploadControllerTest.kt | 1 + .../V2ProjectsControllerCreateTest.kt | 3 +- .../KeyScreenshotControllerTest.kt | 1 + .../SecuredKeyScreenshotControllerTest.kt | 9 ++++-- .../LegacyMigrationTest.kt | 5 ++- backend/testing/build.gradle | 3 +- .../io/tolgee/fixtures/EmailTestUtil.kt | 1 - .../ProjectApiKeyAuthRequestPerformer.kt | 1 - .../kotlin/io/tolgee/fixtures/scopeAssert.kt | 3 +- .../io/tolgee/fixtures/statusExpectations.kt | 5 +-- .../kotlin/io/tolgee/testing/satisfies.kt | 32 +++++++++++++++++++ settings.gradle | 4 +-- 19 files changed, 79 insertions(+), 18 deletions(-) create mode 100644 backend/testing/src/main/kotlin/io/tolgee/testing/satisfies.kt diff --git a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/V2UserControllerTest.kt b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/V2UserControllerTest.kt index 25f1af2680..367f322682 100644 --- a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/V2UserControllerTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/V2UserControllerTest.kt @@ -16,6 +16,7 @@ import io.tolgee.testing.AuthorizedControllerTest import io.tolgee.testing.ContextRecreatingTest import io.tolgee.testing.assert import io.tolgee.testing.assertions.Assertions.assertThat +import io.tolgee.testing.satisfies import org.assertj.core.api.Assertions import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -23,7 +24,6 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.test.web.servlet.result.MockMvcResultMatchers -import java.util.* @ContextRecreatingTest @SpringBootTest( diff --git a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/contentDelivery/ContentDeliveryConfigControllerTest.kt b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/contentDelivery/ContentDeliveryConfigControllerTest.kt index 3d98f154ad..94e134fcb1 100644 --- a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/contentDelivery/ContentDeliveryConfigControllerTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/contentDelivery/ContentDeliveryConfigControllerTest.kt @@ -19,6 +19,7 @@ import io.tolgee.service.contentDelivery.ContentDeliveryConfigService import io.tolgee.testing.ContextRecreatingTest import io.tolgee.testing.annotations.ProjectJWTAuthTestMethod import io.tolgee.testing.assert +import io.tolgee.testing.satisfies import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test diff --git a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/organizationController/OrganizationControllerInvitingTest.kt b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/organizationController/OrganizationControllerInvitingTest.kt index 9e79354bc3..e807c86f60 100644 --- a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/organizationController/OrganizationControllerInvitingTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/organizationController/OrganizationControllerInvitingTest.kt @@ -17,6 +17,7 @@ import io.tolgee.model.enums.OrganizationRoleType import io.tolgee.testing.AuthorizedControllerTest import io.tolgee.testing.assertions.Assertions.assertThat import io.tolgee.testing.assertions.Assertions.assertThatThrownBy +import io.tolgee.testing.satisfies import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired diff --git a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/organizationController/OrganizationControllerTest.kt b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/organizationController/OrganizationControllerTest.kt index 3d305f1906..38f0c3d835 100644 --- a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/organizationController/OrganizationControllerTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/organizationController/OrganizationControllerTest.kt @@ -3,12 +3,22 @@ package io.tolgee.api.v2.controllers.organizationController import io.tolgee.development.testDataBuilder.data.OrganizationTestData import io.tolgee.dtos.request.organization.OrganizationDto import io.tolgee.dtos.request.organization.SetOrganizationRoleDto -import io.tolgee.fixtures.* +import io.tolgee.fixtures.andAssertError +import io.tolgee.fixtures.andAssertThatJson +import io.tolgee.fixtures.andIsBadRequest +import io.tolgee.fixtures.andIsCreated +import io.tolgee.fixtures.andIsForbidden +import io.tolgee.fixtures.andIsNotFound +import io.tolgee.fixtures.andIsOk +import io.tolgee.fixtures.andPrettyPrint +import io.tolgee.fixtures.isPermissionScopes +import io.tolgee.fixtures.node import io.tolgee.model.Organization import io.tolgee.model.enums.OrganizationRoleType import io.tolgee.model.enums.ProjectPermissionType import io.tolgee.testing.assert import io.tolgee.testing.assertions.Assertions.assertThat +import io.tolgee.testing.satisfiesIf import org.junit.jupiter.api.Test import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc import org.springframework.boot.test.context.SpringBootTest @@ -170,7 +180,7 @@ class OrganizationControllerTest : BaseOrganizationControllerTest() { node("name").isEqualTo("Test org") node("slug").isEqualTo("test-org") node("_links.self.href").isEqualTo("http://localhost/v2/organizations/test-org") - node("id").isNumber.satisfies { + node("id").isNumber.satisfiesIf { organizationService.find(it.toLong()) is Organization } } diff --git a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/translations/v2TranslationsController/TranslationsControllerCursorTest.kt b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/translations/v2TranslationsController/TranslationsControllerCursorTest.kt index 8a2e0e5078..7e82b1811f 100644 --- a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/translations/v2TranslationsController/TranslationsControllerCursorTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/translations/v2TranslationsController/TranslationsControllerCursorTest.kt @@ -8,6 +8,7 @@ import io.tolgee.fixtures.andIsOk import io.tolgee.fixtures.andPrettyPrint import io.tolgee.testing.annotations.ProjectJWTAuthTestMethod import io.tolgee.testing.assertions.Assertions.assertThat +import io.tolgee.testing.satisfies import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc diff --git a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/translations/v2TranslationsController/TranslationsControllerModificationTest.kt b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/translations/v2TranslationsController/TranslationsControllerModificationTest.kt index c10c2154d3..d41a89926f 100644 --- a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/translations/v2TranslationsController/TranslationsControllerModificationTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/translations/v2TranslationsController/TranslationsControllerModificationTest.kt @@ -15,6 +15,7 @@ import io.tolgee.model.translation.Translation import io.tolgee.testing.annotations.ProjectApiKeyAuthTestMethod import io.tolgee.testing.annotations.ProjectJWTAuthTestMethod import io.tolgee.testing.assertions.Assertions.assertThat +import io.tolgee.testing.satisfies import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc diff --git a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ImageUploadController/SecuredV2ImageUploadControllerTest.kt b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ImageUploadController/SecuredV2ImageUploadControllerTest.kt index 69e068c4fb..6a2aa307d2 100644 --- a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ImageUploadController/SecuredV2ImageUploadControllerTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ImageUploadController/SecuredV2ImageUploadControllerTest.kt @@ -4,11 +4,17 @@ package io.tolgee.api.v2.controllers.v2ImageUploadController -import io.tolgee.fixtures.* +import io.tolgee.fixtures.andAssertThatJson +import io.tolgee.fixtures.andIsCreated +import io.tolgee.fixtures.andIsNotFound +import io.tolgee.fixtures.andIsOk +import io.tolgee.fixtures.andIsUnauthorized +import io.tolgee.fixtures.andPrettyPrint import io.tolgee.security.authentication.JwtService import io.tolgee.testing.ContextRecreatingTest import io.tolgee.testing.annotations.ProjectJWTAuthTestMethod import io.tolgee.testing.assertions.Assertions.assertThat +import io.tolgee.testing.satisfies import org.assertj.core.data.Offset import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Test @@ -16,7 +22,6 @@ import org.junit.jupiter.api.TestInstance import org.springframework.boot.test.context.SpringBootTest import java.io.File import java.time.Duration -import java.util.* @TestInstance(TestInstance.Lifecycle.PER_CLASS) @ContextRecreatingTest diff --git a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ImageUploadController/V2ImageUploadControllerTest.kt b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ImageUploadController/V2ImageUploadControllerTest.kt index b0dce3b9e6..fcca30f56a 100644 --- a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ImageUploadController/V2ImageUploadControllerTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ImageUploadController/V2ImageUploadControllerTest.kt @@ -12,6 +12,7 @@ import io.tolgee.fixtures.andIsForbidden import io.tolgee.fixtures.andIsOk import io.tolgee.fixtures.andPrettyPrint import io.tolgee.testing.assertions.Assertions.assertThat +import io.tolgee.testing.satisfies import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.Test diff --git a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/V2ProjectsControllerCreateTest.kt b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/V2ProjectsControllerCreateTest.kt index 6aee2a922e..f08a0f5869 100644 --- a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/V2ProjectsControllerCreateTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/V2ProjectsControllerCreateTest.kt @@ -11,6 +11,7 @@ import io.tolgee.fixtures.andIsOk import io.tolgee.fixtures.andPrettyPrint import io.tolgee.testing.AuthorizedControllerTest import io.tolgee.testing.assertions.Assertions.assertThat +import io.tolgee.testing.satisfies import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc @@ -72,7 +73,7 @@ class V2ProjectsControllerCreateTest : AuthorizedControllerTest() { performAuthPost("/v2/projects", request).andIsOk.andAssertThatJson { node("id").asNumber().satisfies { projectService.get(it.toLong()).let { - assertThat(it.organizationOwner?.id).isEqualTo(organization.id) + assertThat(it.organizationOwner.id).isEqualTo(organization.id) } } } diff --git a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ScreenshotController/KeyScreenshotControllerTest.kt b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ScreenshotController/KeyScreenshotControllerTest.kt index f13b2f04c5..9c74679aa2 100644 --- a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ScreenshotController/KeyScreenshotControllerTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ScreenshotController/KeyScreenshotControllerTest.kt @@ -13,6 +13,7 @@ import io.tolgee.fixtures.andPrettyPrint import io.tolgee.testing.annotations.ProjectJWTAuthTestMethod import io.tolgee.testing.assert import io.tolgee.testing.assertions.Assertions.assertThat +import io.tolgee.testing.satisfies import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.Test diff --git a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ScreenshotController/SecuredKeyScreenshotControllerTest.kt b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ScreenshotController/SecuredKeyScreenshotControllerTest.kt index eba534a367..c5f5f6b186 100644 --- a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ScreenshotController/SecuredKeyScreenshotControllerTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ScreenshotController/SecuredKeyScreenshotControllerTest.kt @@ -5,13 +5,19 @@ package io.tolgee.api.v2.controllers.v2ScreenshotController import io.tolgee.dtos.request.key.CreateKeyDto -import io.tolgee.fixtures.* +import io.tolgee.fixtures.andAssertThatJson +import io.tolgee.fixtures.andIsCreated +import io.tolgee.fixtures.andIsNotFound +import io.tolgee.fixtures.andIsOk +import io.tolgee.fixtures.andIsUnauthorized +import io.tolgee.fixtures.generateUniqueString import io.tolgee.model.Permission import io.tolgee.model.enums.Scope import io.tolgee.security.authentication.JwtService import io.tolgee.testing.ContextRecreatingTest import io.tolgee.testing.annotations.ProjectJWTAuthTestMethod import io.tolgee.testing.assertions.Assertions.assertThat +import io.tolgee.testing.satisfies import org.assertj.core.data.Offset import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Test @@ -19,7 +25,6 @@ import org.junit.jupiter.api.TestInstance import org.springframework.boot.test.context.SpringBootTest import java.io.File import java.time.Duration -import java.util.* @ContextRecreatingTest @SpringBootTest( diff --git a/backend/app/src/test/kotlin/io/tolgee/initial_user_creation/LegacyMigrationTest.kt b/backend/app/src/test/kotlin/io/tolgee/initial_user_creation/LegacyMigrationTest.kt index f56386dced..8a26759507 100644 --- a/backend/app/src/test/kotlin/io/tolgee/initial_user_creation/LegacyMigrationTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/initial_user_creation/LegacyMigrationTest.kt @@ -16,7 +16,10 @@ import io.tolgee.repository.UserAccountRepository import io.tolgee.service.security.SecurityService import io.tolgee.testing.ContextRecreatingTest import io.tolgee.testing.assertions.Assertions.assertThat -import org.junit.jupiter.api.* +import io.tolgee.testing.satisfies +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.assertDoesNotThrow import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.transaction.annotation.Transactional diff --git a/backend/testing/build.gradle b/backend/testing/build.gradle index 5081f578dd..93ac9d3921 100644 --- a/backend/testing/build.gradle +++ b/backend/testing/build.gradle @@ -77,8 +77,7 @@ dependencies { implementation "org.springframework.boot:spring-boot-starter-validation" implementation("org.springframework.boot:spring-boot-starter-security") implementation 'org.springframework.boot:spring-boot-starter-mail' - implementation('org.springframework.boot:spring-boot-starter-test') { - } + implementation('org.springframework.boot:spring-boot-starter-test') kapt "org.springframework.boot:spring-boot-configuration-processor" implementation "org.springframework.boot:spring-boot-configuration-processor" api "org.springframework.boot:spring-boot-starter-actuator" diff --git a/backend/testing/src/main/kotlin/io/tolgee/fixtures/EmailTestUtil.kt b/backend/testing/src/main/kotlin/io/tolgee/fixtures/EmailTestUtil.kt index 1176af0998..7ede747adc 100644 --- a/backend/testing/src/main/kotlin/io/tolgee/fixtures/EmailTestUtil.kt +++ b/backend/testing/src/main/kotlin/io/tolgee/fixtures/EmailTestUtil.kt @@ -55,7 +55,6 @@ class EmailTestUtil() { val assertEmailTo: AbstractStringAssert<*> get() { - @Suppress("CAST_NEVER_SUCCEEDS") return Assertions.assertThat(messageArgumentCaptor.firstValue.getHeader("To")[0] as String) } } diff --git a/backend/testing/src/main/kotlin/io/tolgee/fixtures/ProjectApiKeyAuthRequestPerformer.kt b/backend/testing/src/main/kotlin/io/tolgee/fixtures/ProjectApiKeyAuthRequestPerformer.kt index 9c826e7ac6..af831c76be 100644 --- a/backend/testing/src/main/kotlin/io/tolgee/fixtures/ProjectApiKeyAuthRequestPerformer.kt +++ b/backend/testing/src/main/kotlin/io/tolgee/fixtures/ProjectApiKeyAuthRequestPerformer.kt @@ -12,7 +12,6 @@ import org.springframework.stereotype.Component import org.springframework.test.web.servlet.ResultActions import org.springframework.test.web.servlet.request.MockMvcRequestBuilders -@Suppress("SpringJavaInjectionPointsAutowiringInspection") @Component @org.springframework.context.annotation.Scope("prototype") class ProjectApiKeyAuthRequestPerformer( diff --git a/backend/testing/src/main/kotlin/io/tolgee/fixtures/scopeAssert.kt b/backend/testing/src/main/kotlin/io/tolgee/fixtures/scopeAssert.kt index 8e85e4cf72..8f21f49655 100644 --- a/backend/testing/src/main/kotlin/io/tolgee/fixtures/scopeAssert.kt +++ b/backend/testing/src/main/kotlin/io/tolgee/fixtures/scopeAssert.kt @@ -4,11 +4,12 @@ import io.tolgee.model.enums.ProjectPermissionType import io.tolgee.model.enums.Scope import io.tolgee.model.enums.unpack import io.tolgee.testing.assertions.Assertions +import io.tolgee.testing.satisfies import org.assertj.core.api.ObjectArrayAssert fun ObjectArrayAssert.equalsPermissionType( permissionType: ProjectPermissionType -): ObjectArrayAssert? { +): ObjectArrayAssert { return this.satisfies { Assertions.assertThat(it.unpack()).containsExactlyInAnyOrder(*permissionType.availableScopes.unpack()) } diff --git a/backend/testing/src/main/kotlin/io/tolgee/fixtures/statusExpectations.kt b/backend/testing/src/main/kotlin/io/tolgee/fixtures/statusExpectations.kt index eb6963b15a..0c88300a8d 100644 --- a/backend/testing/src/main/kotlin/io/tolgee/fixtures/statusExpectations.kt +++ b/backend/testing/src/main/kotlin/io/tolgee/fixtures/statusExpectations.kt @@ -6,6 +6,7 @@ import io.tolgee.constants.Message import io.tolgee.model.enums.ProjectPermissionType import io.tolgee.model.enums.Scope import io.tolgee.testing.assertions.Assertions.assertThat +import io.tolgee.testing.assertions.ErrorResponseAssert import io.tolgee.testing.assertions.MvcResultAssert import net.javacrumbs.jsonunit.assertj.JsonAssert import net.javacrumbs.jsonunit.assertj.assertThatJson @@ -77,14 +78,14 @@ fun ResultActions.tryPrettyPrinting(fn: ResultActions.() -> ResultActions): Resu } } -val ResultActions.andGetContentAsString +val ResultActions.andGetContentAsString: String get() = this.andReturn().response.getContentAsString(StandardCharsets.UTF_8) val ResultActions.andGetContentAsJsonMap @Suppress("UNCHECKED_CAST") get() = jacksonObjectMapper().readValue(andGetContentAsString, MutableMap::class.java) as MutableMap -val ResultActions.andAssertError +val ResultActions.andAssertError: ErrorResponseAssert get() = assertThat(this.andReturn()).error() val ResultActions.andPrettyPrint: ResultActions diff --git a/backend/testing/src/main/kotlin/io/tolgee/testing/satisfies.kt b/backend/testing/src/main/kotlin/io/tolgee/testing/satisfies.kt new file mode 100644 index 0000000000..a39ab32b90 --- /dev/null +++ b/backend/testing/src/main/kotlin/io/tolgee/testing/satisfies.kt @@ -0,0 +1,32 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.testing + +import org.assertj.core.api.AbstractAssert +import org.assertj.core.api.Condition +import org.assertj.core.api.ThrowingConsumer + +// https://github.com/assertj/assertj/issues/2357 +fun , E> AbstractAssert.satisfies(fn: (actual: E) -> Unit): S { + return satisfies(ThrowingConsumer { fn(it) }) +} + +fun , E> AbstractAssert.satisfiesIf(fn: (actual: E) -> Boolean): S { + return satisfies(object : Condition() { + override fun matches(value: E): Boolean = fn(value) + }) +} diff --git a/settings.gradle b/settings.gradle index bc0c663417..754b69525d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -42,12 +42,12 @@ dependencyResolutionManagement { library('jjwtApi', 'io.jsonwebtoken', 'jjwt-api').version(jjwtVersion) library('jjwtImpl', 'io.jsonwebtoken', 'jjwt-impl').version(jjwtVersion) library('jjwtJackson', 'io.jsonwebtoken', 'jjwt-jackson').version(jjwtVersion) - library('assertJCore', 'org.assertj:assertj-core:3.19.0') + library('assertJCore', 'org.assertj:assertj-core:3.24.2') library('springmockk', 'com.ninja-squad:springmockk:3.0.1') library('mockito', 'org.mockito.kotlin:mockito-kotlin:5.0.0') library('commonsCodec', 'commons-codec:commons-codec:1.15') library('icu4j', 'com.ibm.icu:icu4j:69.1') - library('jsonUnitAssert', 'net.javacrumbs.json-unit:json-unit-assertj:2.28.0') + library('jsonUnitAssert', 'net.javacrumbs.json-unit:json-unit-assertj:2.38.0') library('amazonS3', "software.amazon.awssdk:s3:$amazonAwsSdkVersion") library('amazonSTS', "software.amazon.awssdk:sts:$amazonAwsSdkVersion") library('amazonTranslate', "software.amazon.awssdk:translate:$amazonAwsSdkVersion") From 9f1c7cdfaa58a44b33d95d348a4432ea2c000127 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Sun, 3 Dec 2023 16:24:51 +0100 Subject: [PATCH 10/44] feat: debounce key creation and initial string creations --- .../notifications/AbstractNotificationTest.kt | 4 +- .../RemappedNotificationsTest.kt | 155 ++++++++++++------ .../UserNotificationTranslationTest.kt | 100 +++++++++++ .../tolgee/notifications/NotificationType.kt | 16 +- .../UserNotificationDebouncer.kt | 73 +++++++-- .../listeners/ActivityEventListener.kt | 76 +++++++-- .../repository/UserNotificationRepository.kt | 45 ++++- 7 files changed, 365 insertions(+), 104 deletions(-) create mode 100644 backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationTranslationTest.kt diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt index 7f0187d028..52ca7d38de 100644 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt @@ -94,14 +94,14 @@ abstract class AbstractNotificationTest : AuthorizedControllerTest() { } fun waitUntilUserNotificationDispatch(count: Int = 1) { - val dispatched = semaphore.tryAcquire(count, 2L, TimeUnit.SECONDS) + val dispatched = semaphore.tryAcquire(count, 1L, TimeUnit.SECONDS) dispatched.assert .withFailMessage("Expected at least $count notification(s) to be dispatched.") .isTrue() } fun ensureNoUserNotificationDispatch() { - val dispatched = semaphore.tryAcquire(2L, TimeUnit.SECONDS) + val dispatched = semaphore.tryAcquire(1L, TimeUnit.SECONDS) dispatched.assert .withFailMessage("Expected no notifications to be dispatched.") .isFalse() diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/RemappedNotificationsTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/RemappedNotificationsTest.kt index d183c1738b..5cf19713e9 100644 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/RemappedNotificationsTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/RemappedNotificationsTest.kt @@ -49,7 +49,7 @@ class RemappedNotificationsTest : AbstractNotificationTest() { performAuthPut("/v2/projects/${testData.project1.id}/import/apply?forceMode=OVERRIDE", null).andIsOk - waitUntilUserNotificationDispatch(14) + waitUntilUserNotificationDispatch(12) val acmeChiefNotifications = userNotificationRepository.findAllByRecipient(testData.orgAdmin) val projectManagerNotifications = userNotificationRepository.findAllByRecipient(testData.projectManager) val frenchTranslatorNotifications = userNotificationRepository.findAllByRecipient(testData.frenchTranslator) @@ -62,45 +62,81 @@ class RemappedNotificationsTest : AbstractNotificationTest() { acmeChiefNotifications.assert.hasSize(2) projectManagerNotifications.assert.hasSize(2) frenchTranslatorNotifications.assert.hasSize(2) - czechTranslatorNotifications.assert.hasSize(2) - germanTranslatorNotifications.assert.hasSize(2) + czechTranslatorNotifications.assert.hasSize(1) + germanTranslatorNotifications.assert.hasSize(1) frenchCzechTranslatorNotifications.assert.hasSize(2) bobNotifications.assert.hasSize(2) - acmeChiefNotifications.find { it.type == NotificationType.ACTIVITY_KEYS_CREATED }!! - .modifiedEntities.assert.hasSize(2) - acmeChiefNotifications.find { it.type == NotificationType.ACTIVITY_TRANSLATIONS_UPDATED }!! - .modifiedEntities.assert.hasSize(7) - - projectManagerNotifications.find { it.type == NotificationType.ACTIVITY_KEYS_CREATED }!! - .modifiedEntities.assert.hasSize(2) - projectManagerNotifications.find { it.type == NotificationType.ACTIVITY_TRANSLATIONS_UPDATED }!! - .modifiedEntities.assert.hasSize(7) - - frenchTranslatorNotifications.find { it.type == NotificationType.ACTIVITY_KEYS_CREATED }!! - .modifiedEntities.assert.hasSize(2) - frenchTranslatorNotifications.find { it.type == NotificationType.ACTIVITY_TRANSLATIONS_UPDATED }!! - .modifiedEntities.assert.hasSize(5) - - czechTranslatorNotifications.find { it.type == NotificationType.ACTIVITY_KEYS_CREATED }!! - .modifiedEntities.assert.hasSize(2) - czechTranslatorNotifications.find { it.type == NotificationType.ACTIVITY_TRANSLATIONS_UPDATED }!! - .modifiedEntities.assert.hasSize(4) - - germanTranslatorNotifications.find { it.type == NotificationType.ACTIVITY_KEYS_CREATED }!! - .modifiedEntities.assert.hasSize(2) - germanTranslatorNotifications.find { it.type == NotificationType.ACTIVITY_TRANSLATIONS_UPDATED }!! - .modifiedEntities.assert.hasSize(2) - - frenchCzechTranslatorNotifications.find { it.type == NotificationType.ACTIVITY_KEYS_CREATED }!! - .modifiedEntities.assert.hasSize(2) - frenchCzechTranslatorNotifications.find { it.type == NotificationType.ACTIVITY_TRANSLATIONS_UPDATED }!! - .modifiedEntities.assert.hasSize(7) - - bobNotifications.find { it.type == NotificationType.ACTIVITY_KEYS_CREATED }!! - .modifiedEntities.assert.hasSize(2) - bobNotifications.find { it.type == NotificationType.ACTIVITY_TRANSLATIONS_UPDATED }!! - .modifiedEntities.assert.hasSize(7) + acmeChiefNotifications.assert + .noneSatisfy { it.type.assert.isEqualTo(NotificationType.ACTIVITY_SOURCE_STRINGS_UPDATED) } + .satisfiesOnlyOnce { + it.type.assert.isEqualTo(NotificationType.ACTIVITY_TRANSLATIONS_UPDATED) + it.modifiedEntities.assert.hasSize(1) + } + .satisfiesOnlyOnce { + it.type.assert.isEqualTo(NotificationType.ACTIVITY_KEYS_CREATED) + it.modifiedEntities.assert.hasSize(8) // 2 keys + 6 translations + } + + projectManagerNotifications.assert + .noneSatisfy { it.type.assert.isEqualTo(NotificationType.ACTIVITY_SOURCE_STRINGS_UPDATED) } + .satisfiesOnlyOnce { + it.type.assert.isEqualTo(NotificationType.ACTIVITY_TRANSLATIONS_UPDATED) + it.modifiedEntities.assert.hasSize(1) + } + .satisfiesOnlyOnce { + it.type.assert.isEqualTo(NotificationType.ACTIVITY_KEYS_CREATED) + it.modifiedEntities.assert.hasSize(8) // 2 keys + 6 translations + } + + frenchTranslatorNotifications.assert + .noneSatisfy { it.type.assert.isEqualTo(NotificationType.ACTIVITY_SOURCE_STRINGS_UPDATED) } + .satisfiesOnlyOnce { + it.type.assert.isEqualTo(NotificationType.ACTIVITY_TRANSLATIONS_UPDATED) + it.modifiedEntities.assert.hasSize(1) + } + .satisfiesOnlyOnce { + it.type.assert.isEqualTo(NotificationType.ACTIVITY_KEYS_CREATED) + it.modifiedEntities.assert.hasSize(6) // 2 keys + 4 translations + } + + czechTranslatorNotifications.assert + .noneSatisfy { it.type.assert.isEqualTo(NotificationType.ACTIVITY_SOURCE_STRINGS_UPDATED) } + .noneSatisfy { it.type.assert.isEqualTo(NotificationType.ACTIVITY_TRANSLATIONS_UPDATED) } + .satisfiesOnlyOnce { + it.type.assert.isEqualTo(NotificationType.ACTIVITY_KEYS_CREATED) + it.modifiedEntities.assert.hasSize(6) // 2 keys + 4 translations + } + + germanTranslatorNotifications.assert + .noneSatisfy { it.type.assert.isEqualTo(NotificationType.ACTIVITY_SOURCE_STRINGS_UPDATED) } + .noneSatisfy { it.type.assert.isEqualTo(NotificationType.ACTIVITY_TRANSLATIONS_UPDATED) } + .satisfiesOnlyOnce { + it.type.assert.isEqualTo(NotificationType.ACTIVITY_KEYS_CREATED) + it.modifiedEntities.assert.hasSize(4) // 2 keys + 2 translations + } + + frenchCzechTranslatorNotifications.assert + .noneSatisfy { it.type.assert.isEqualTo(NotificationType.ACTIVITY_SOURCE_STRINGS_UPDATED) } + .satisfiesOnlyOnce { + it.type.assert.isEqualTo(NotificationType.ACTIVITY_TRANSLATIONS_UPDATED) + it.modifiedEntities.assert.hasSize(1) + } + .satisfiesOnlyOnce { + it.type.assert.isEqualTo(NotificationType.ACTIVITY_KEYS_CREATED) + it.modifiedEntities.assert.hasSize(8) // 2 keys + 6 translations + } + + bobNotifications.assert + .noneSatisfy { it.type.assert.isEqualTo(NotificationType.ACTIVITY_SOURCE_STRINGS_UPDATED) } + .satisfiesOnlyOnce { + it.type.assert.isEqualTo(NotificationType.ACTIVITY_TRANSLATIONS_UPDATED) + it.modifiedEntities.assert.hasSize(1) + } + .satisfiesOnlyOnce { + it.type.assert.isEqualTo(NotificationType.ACTIVITY_KEYS_CREATED) + it.modifiedEntities.assert.hasSize(8) // 2 keys + 6 translations + } ensureNoUserNotificationDispatch() } @@ -115,7 +151,7 @@ class RemappedNotificationsTest : AbstractNotificationTest() { generateImage(100, 100).inputStream.readAllBytes() ) ) - ).andIsCreated.andGetContentAsJsonMap["id"] as Long + ).andIsCreated.andGetContentAsJsonMap["id"].let { (it as Int).toLong() } performAuthPut( "/v2/projects/${testData.project1.id}/keys/${testData.keyProject1.id}/complex-update", @@ -129,25 +165,46 @@ class RemappedNotificationsTest : AbstractNotificationTest() { ) ).andIsOk - waitUntilUserNotificationDispatch(20) + waitUntilUserNotificationDispatch(25) val acmeChiefNotifications = userNotificationRepository.findAllByRecipient(testData.orgAdmin) val czechTranslatorNotifications = userNotificationRepository.findAllByRecipient(testData.czechTranslator) val bobNotifications = userNotificationRepository.findAllByRecipient(testData.bob) bobNotifications.assert - .hasSize(2) - .noneMatch { it.type == NotificationType.ACTIVITY_KEYS_SCREENSHOTS_UPLOADED } + .hasSize(3) + .noneSatisfy { + it.type.assert.isEqualTo(NotificationType.ACTIVITY_KEYS_SCREENSHOTS_UPLOADED) + } acmeChiefNotifications.assert + .hasSize(4) + .satisfiesOnlyOnce { + it.type.assert.isEqualTo(NotificationType.ACTIVITY_KEYS_UPDATED) + } + .satisfiesOnlyOnce { + it.type.assert.isEqualTo(NotificationType.ACTIVITY_KEYS_SCREENSHOTS_UPLOADED) + } + .satisfiesOnlyOnce { + it.type.assert.isEqualTo(NotificationType.ACTIVITY_SOURCE_STRINGS_UPDATED) + it.modifiedEntities.assert.hasSize(1) + } + .satisfiesOnlyOnce { + it.type.assert.isEqualTo(NotificationType.ACTIVITY_TRANSLATIONS_UPDATED) + it.modifiedEntities.assert.hasSize(1) + } + + czechTranslatorNotifications.assert .hasSize(3) - .anyMatch { it.type == NotificationType.ACTIVITY_KEYS_UPDATED } - .anyMatch { it.type == NotificationType.ACTIVITY_KEYS_SCREENSHOTS_UPLOADED } - .anyMatch { it.type == NotificationType.ACTIVITY_TRANSLATIONS_UPDATED && it.modifiedEntities.size == 2 } - - czechTranslatorNotifications.assert.hasSize(3) - .anyMatch { it.type == NotificationType.ACTIVITY_KEYS_UPDATED } - .anyMatch { it.type == NotificationType.ACTIVITY_KEYS_SCREENSHOTS_UPLOADED } - .anyMatch { it.type == NotificationType.ACTIVITY_TRANSLATIONS_UPDATED && it.modifiedEntities.size == 1 } + .satisfiesOnlyOnce { + it.type.assert.isEqualTo(NotificationType.ACTIVITY_KEYS_UPDATED) + } + .satisfiesOnlyOnce { + it.type.assert.isEqualTo(NotificationType.ACTIVITY_KEYS_SCREENSHOTS_UPLOADED) + } + .satisfiesOnlyOnce { + it.type.assert.isEqualTo(NotificationType.ACTIVITY_SOURCE_STRINGS_UPDATED) + it.modifiedEntities.assert.hasSize(1) + } ensureNoUserNotificationDispatch() } diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationTranslationTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationTranslationTest.kt new file mode 100644 index 0000000000..e55756babd --- /dev/null +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationTranslationTest.kt @@ -0,0 +1,100 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.notifications + +import io.tolgee.dtos.request.key.CreateKeyDto +import io.tolgee.dtos.request.translation.SetTranslationsWithKeyDto +import io.tolgee.fixtures.andIsCreated +import io.tolgee.fixtures.andIsOk +import io.tolgee.testing.assert +import org.junit.jupiter.api.Test + +class UserNotificationTranslationTest : AbstractNotificationTest() { + @Test + fun `it does not dispatch the same type of notification for source strings and translated strings`() { + performAuthPut( + url = "/v2/projects/${testData.calmProject.id}/translations", + content = SetTranslationsWithKeyDto( + key = testData.keyCalmProject.name, + translations = mapOf("en" to "Superb English translation!") + ) + ).andIsOk + + waitUntilUserNotificationDispatch() + + userNotificationRepository.findAllByRecipient(testData.alice).assert + .satisfiesOnlyOnce { it.type.assert.isEqualTo(NotificationType.ACTIVITY_SOURCE_STRINGS_UPDATED) } + .noneSatisfy { it.type.assert.isEqualTo(NotificationType.ACTIVITY_TRANSLATIONS_UPDATED) } + + performAuthPut( + url = "/v2/projects/${testData.calmProject.id}/translations", + content = SetTranslationsWithKeyDto( + key = testData.keyCalmProject.name, + translations = mapOf("fr" to "Superb French translation!") + ) + ).andIsOk + + waitUntilUserNotificationDispatch() + + userNotificationRepository.findAllByRecipient(testData.alice).assert + .satisfiesOnlyOnce { it.type.assert.isEqualTo(NotificationType.ACTIVITY_SOURCE_STRINGS_UPDATED) } + .satisfiesOnlyOnce { it.type.assert.isEqualTo(NotificationType.ACTIVITY_TRANSLATIONS_UPDATED) } + } + + @Test + fun `it does debounce key creation and setting strings as a single notification`() { + performAuthPost( + "/v2/projects/${testData.calmProject.id}/keys/create", + CreateKeyDto(name = "test-key") + ).andIsCreated + + waitUntilUserNotificationDispatch() + + performAuthPut( + url = "/v2/projects/${testData.calmProject.id}/translations", + content = SetTranslationsWithKeyDto( + key = "test-key", + translations = mapOf("en" to "Superb English translation!", "fr" to "Superb French translation!") + ) + ).andIsOk + + waitUntilUserNotificationDispatch() + + println(userNotificationRepository.findAllByRecipient(testData.alice).map { it.type }) + userNotificationRepository.findAllByRecipient(testData.alice).assert.hasSize(1) + } + + @Test + fun `it does not dispatch outdated notifications if it was not done manually`() { + performAuthPut( + url = "/v2/projects/${testData.calmProject.id}/translations", + content = SetTranslationsWithKeyDto( + key = testData.keyCalmProject.name, + translations = mapOf("en" to "Superb English translation!") + ) + ).andIsOk + + waitUntilUserNotificationDispatch() + + userNotificationRepository.findAllByRecipient(testData.alice).assert + .noneMatch { it.type == NotificationType.ACTIVITY_TRANSLATION_OUTDATED } + .satisfiesOnlyOnce { + it.type.assert.isEqualTo(NotificationType.ACTIVITY_TRANSLATIONS_UPDATED) + it.modifiedEntities.assert.noneSatisfy { e -> e.modifications.assert.hasOnlyFields("outdated") } + } + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationType.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationType.kt index a06ef0245e..1b13671bce 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationType.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationType.kt @@ -23,11 +23,11 @@ enum class NotificationType { ACTIVITY_KEYS_CREATED, ACTIVITY_KEYS_UPDATED, ACTIVITY_KEYS_SCREENSHOTS_UPLOADED, + ACTIVITY_SOURCE_STRINGS_UPDATED, ACTIVITY_TRANSLATIONS_UPDATED, - ACTIVITY_TRANSLATIONS_DELETED, - ACTIVITY_MARKED_AS_OUTDATED, - ACTIVITY_MARKED_AS_REVIEWED, - ACTIVITY_MARKED_AS_UNREVIEWED, + ACTIVITY_TRANSLATION_OUTDATED, + ACTIVITY_TRANSLATION_REVIEWED, + ACTIVITY_TRANSLATION_UNREVIEWED, ACTIVITY_NEW_COMMENTS, ACTIVITY_COMMENTS_MENTION, @@ -40,11 +40,11 @@ enum class NotificationType { ACTIVITY_KEYS_CREATED, ACTIVITY_KEYS_UPDATED, ACTIVITY_KEYS_SCREENSHOTS_UPLOADED, + ACTIVITY_SOURCE_STRINGS_UPDATED, ACTIVITY_TRANSLATIONS_UPDATED, - ACTIVITY_TRANSLATIONS_DELETED, - ACTIVITY_MARKED_AS_OUTDATED, - ACTIVITY_MARKED_AS_REVIEWED, - ACTIVITY_MARKED_AS_UNREVIEWED, + ACTIVITY_TRANSLATION_OUTDATED, + ACTIVITY_TRANSLATION_REVIEWED, + ACTIVITY_TRANSLATION_UNREVIEWED, ACTIVITY_NEW_COMMENTS, ACTIVITY_COMMENTS_MENTION, ) diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationDebouncer.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationDebouncer.kt index 6d1b3c27c6..1bddd262ce 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationDebouncer.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationDebouncer.kt @@ -16,8 +16,11 @@ package io.tolgee.notifications +import io.tolgee.model.Project import io.tolgee.model.UserAccount import io.tolgee.model.UserNotification +import io.tolgee.model.activity.ActivityModifiedEntity +import io.tolgee.model.translation.Translation import io.tolgee.model.translation.TranslationComment import io.tolgee.notifications.dto.NotificationCreateDto import io.tolgee.notifications.dto.UserNotificationParamsDto @@ -78,37 +81,71 @@ class UserNotificationDebouncer( notificationDto: NotificationCreateDto, recipients: List, ): Map { - if (commentNotificationTypes.contains(notificationDto.type)) - return fetchRelevantCommentActivityNotifications(notificationDto, recipients) + val notifications = when { + translationUpdateNotificationTypes.contains(notificationDto.type) -> + findCandidatesForTranslationUpdateNotificationDebouncing( + notificationDto.type, + notificationDto.project, + recipients, + notificationDto.modifiedEntities, + ) - val notifications = userNotificationRepository.findCandidatesForNotificationDebouncing( - notificationDto.type, - notificationDto.project, - recipients, - ) + commentNotificationTypes.contains(notificationDto.type) -> + findCandidatesForCommentNotificationDebouncing( + notificationDto.project, + recipients, + notificationDto.modifiedEntities, + ) + + else -> + userNotificationRepository.findCandidatesForNotificationDebouncing( + notificationDto.type, + notificationDto.project, + recipients, + ) + } return notifications.associateBy { it.recipient.id } } - private fun fetchRelevantCommentActivityNotifications( - notificationDto: NotificationCreateDto, + private fun findCandidatesForTranslationUpdateNotificationDebouncing( + type: NotificationType, + project: Project, recipients: List, - ): Map { - val translationId = notificationDto.modifiedEntities - ?.find { it.entityClass == TranslationComment::class.simpleName } - ?.describingRelations?.get("translation")?.entityId - ?: return emptyMap() + entities: List?, + ): List { + val keyId = entities?.find { it.entityClass == Translation::class.simpleName } + ?.describingRelations?.get("key")?.entityId ?: 0L - val notifications = userNotificationRepository.findCandidatesForCommentNotificationDebouncing( - notificationDto.project, + return userNotificationRepository.findCandidatesForTranslationUpdateNotificationDebouncing( + type, + project, recipients, - translationId, + keyId, ) + } - return notifications.associateBy { it.recipient.id } + private fun findCandidatesForCommentNotificationDebouncing( + project: Project, + recipients: List, + entities: List?, + ): List { + val translationId = entities?.find { it.entityClass == TranslationComment::class.simpleName } + ?.describingRelations?.get("translation")?.entityId ?: 0L + + return userNotificationRepository.findCandidatesForCommentNotificationDebouncing( + project, + recipients, + translationId, + ) } companion object { + val translationUpdateNotificationTypes: EnumSet = EnumSet.of( + NotificationType.ACTIVITY_SOURCE_STRINGS_UPDATED, + NotificationType.ACTIVITY_TRANSLATIONS_UPDATED, + ) + val commentNotificationTypes: EnumSet = EnumSet.of( NotificationType.ACTIVITY_NEW_COMMENTS, NotificationType.ACTIVITY_COMMENTS_MENTION, diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt index 52af0a7e30..5d7f17bf3a 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt @@ -86,10 +86,9 @@ class ActivityEventListener( ActivityType.SCREENSHOT_ADD -> processScreenshotUpdate(project, responsibleUser, e) - // ACTIVITY_TRANSLATIONS_*, ACTIVITY_MARKED_AS_OUTDATED, ACTIVITY_MARKED_AS_(UN)REVIEWED + // ACTIVITY_TRANSLATIONS_* ActivityType.SET_TRANSLATIONS, ActivityType.SET_TRANSLATION_STATE, - ActivityType.SET_OUTDATED_FLAG, ActivityType.BATCH_PRE_TRANSLATE_BY_TM, ActivityType.BATCH_MACHINE_TRANSLATE, ActivityType.AUTO_TRANSLATE, @@ -98,11 +97,14 @@ class ActivityEventListener( ActivityType.BATCH_SET_TRANSLATION_STATE -> processSetTranslations(project, responsibleUser, e) + ActivityType.SET_OUTDATED_FLAG -> + processOutdatedFlagUpdate(project, responsibleUser, e) + // ACTIVITY_NEW_COMMENTS (ACTIVITY_COMMENTS_MENTION is user-specific and not computed here) ActivityType.TRANSLATION_COMMENT_ADD -> processSimpleActivity(NotificationType.ACTIVITY_NEW_COMMENTS, project, responsibleUser, e) - // ACTIVITY_DATA_IMPORTED + // ACTIVITY_KEYS_CREATED, ACTIVITY_TRANSLATIONS_* ActivityType.IMPORT -> processImport(project, responsibleUser, e) @@ -197,8 +199,13 @@ class ActivityEventListener( project: Project, responsibleUser: UserAccount?, e: OnProjectActivityStoredEvent, + modifiedEntities: List = e.activityRevision.modifiedEntities ) { - val sortedTranslations = sortTranslations(e.activityRevision.modifiedEntities) + val sortedTranslations = sortTranslations( + modifiedEntities, + baseLanguage = project.baseLanguage?.id ?: 0L + ) + for ((type, translations) in sortedTranslations) { if (translations.isNotEmpty()) { applicationEventPublisher.publishEvent( @@ -212,10 +219,9 @@ class ActivityEventListener( } } - private fun sortTranslations(entities: List): SortedTranslations { + private fun sortTranslations(entities: List, baseLanguage: Long): SortedTranslations { + val updatedSourceTranslations = mutableListOf() val updatedTranslations = mutableListOf() - val deletedTranslations = mutableListOf() - val outdatedTranslations = mutableListOf() val reviewedTranslations = mutableListOf() val unreviewedTranslations = mutableListOf() @@ -224,28 +230,52 @@ class ActivityEventListener( val text = it.modifications["text"] val state = it.modifications["state"] - val outdated = it.modifications["outdated"] if (text != null) { - if (text.new == null) deletedTranslations.add(it) - else updatedTranslations.add(it) + val languageId = it.describingRelations?.get("language")?.entityId + if (languageId == baseLanguage) + updatedSourceTranslations.add(it) + else + updatedTranslations.add(it) } - if (outdated?.new == true) outdatedTranslations.add(it) - if (state?.new == TranslationState.REVIEWED.name) outdatedTranslations.add(it) + if (state?.new == TranslationState.REVIEWED.name) + reviewedTranslations.add(it) if (state?.new == TranslationState.TRANSLATED.name && state.old == TranslationState.REVIEWED.name) unreviewedTranslations.add(it) } return listOf( + Pair(NotificationType.ACTIVITY_SOURCE_STRINGS_UPDATED, updatedSourceTranslations), Pair(NotificationType.ACTIVITY_TRANSLATIONS_UPDATED, updatedTranslations), - Pair(NotificationType.ACTIVITY_TRANSLATIONS_DELETED, deletedTranslations), - Pair(NotificationType.ACTIVITY_MARKED_AS_OUTDATED, outdatedTranslations), - Pair(NotificationType.ACTIVITY_MARKED_AS_REVIEWED, reviewedTranslations), - Pair(NotificationType.ACTIVITY_MARKED_AS_UNREVIEWED, unreviewedTranslations), + Pair(NotificationType.ACTIVITY_TRANSLATION_REVIEWED, reviewedTranslations), + Pair(NotificationType.ACTIVITY_TRANSLATION_UNREVIEWED, unreviewedTranslations), ) } + private fun processOutdatedFlagUpdate( + project: Project, + responsibleUser: UserAccount?, + e: OnProjectActivityStoredEvent, + ) { + val outdatedTranslations = e.activityRevision.modifiedEntities + .filter { it.modifications["outdated"]?.new == true } + + if (outdatedTranslations.isNotEmpty()) { + applicationEventPublisher.publishEvent( + NotificationCreateEvent( + NotificationCreateDto( + type = NotificationType.ACTIVITY_TRANSLATION_OUTDATED, + project = project, + modifiedEntities = outdatedTranslations.toMutableList() + ), + responsibleUser, + source = e, + ) + ) + } + } + private fun processScreenshotUpdate( project: Project, responsibleUser: UserAccount?, @@ -276,9 +306,17 @@ class ActivityEventListener( ) { val createdKeys = e.activityRevision.modifiedEntities .filter { it.entityClass == Key::class.simpleName && it.revisionType == RevisionType.ADD } + .toMutableList() + + val keyIds = createdKeys.map { it.entityId }.toSet() + val updatedTranslations = e.activityRevision.modifiedEntities + .filter { + val isFromNewKey = keyIds.contains(it.describingRelations?.get("key")?.entityId ?: 0L) + if (isFromNewKey) createdKeys.add(it) + !isFromNewKey + } if (createdKeys.isNotEmpty()) { - println("new keys") applicationEventPublisher.publishEvent( NotificationCreateEvent( NotificationCreateDto(NotificationType.ACTIVITY_KEYS_CREATED, project, createdKeys.toMutableList()), @@ -288,6 +326,8 @@ class ActivityEventListener( ) } - processSetTranslations(project, responsibleUser, e) + if (updatedTranslations.isNotEmpty()) { + processSetTranslations(project, responsibleUser, e, updatedTranslations) + } } } diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/UserNotificationRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/UserNotificationRepository.kt index 3210114439..0c634ff7da 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/UserNotificationRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/UserNotificationRepository.kt @@ -39,9 +39,11 @@ interface UserNotificationRepository : JpaRepository { @Query( """ FROM UserNotification un + INNER JOIN un.modifiedEntities me + INNER JOIN ActivityDescribingEntity de ON de.activityRevision = me.activityRevision WHERE - un.unread = true AND un.type = :type AND + un.unread = true AND un.project = :project AND un.recipient IN :recipients """ @@ -52,9 +54,30 @@ interface UserNotificationRepository : JpaRepository { recipients: Collection, ): List - @Modifying - @Query("UPDATE UserNotification un SET un.unread = false WHERE un.recipient = ?1 AND un.id IN ?2") - fun markAsRead(recipient: UserAccount, notifications: Collection) + @Query( + """ + SELECT un + FROM UserNotification un + INNER JOIN un.modifiedEntities me + WHERE + un.unread = true AND + un.project = :project AND + un.recipient IN :recipients AND ( + un.type = :type OR ( + un.type = io.tolgee.notifications.NotificationType.ACTIVITY_KEYS_CREATED AND + me.entityClass = 'Key' AND + me.entityId = :keyId + ) + ) + ORDER BY un.type DESC + """ + ) + fun findCandidatesForTranslationUpdateNotificationDebouncing( + type: NotificationType, + project: Project, + recipients: Collection, + keyId: Long, + ): List @Query( """ @@ -64,15 +87,15 @@ interface UserNotificationRepository : JpaRepository { INNER JOIN ActivityDescribingEntity de ON de.activityRevision = me.activityRevision WHERE un.unread = true AND - un.type IN ( - io.tolgee.notifications.NotificationType.ACTIVITY_NEW_COMMENTS, - io.tolgee.notifications.NotificationType.ACTIVITY_COMMENTS_MENTION - ) AND me.entityClass = 'TranslationComment' AND de.entityClass = 'Translation' AND de.entityId = :translationId AND un.project = :project AND - un.recipient IN :recipients + un.recipient IN :recipients AND + un.type IN ( + io.tolgee.notifications.NotificationType.ACTIVITY_NEW_COMMENTS, + io.tolgee.notifications.NotificationType.ACTIVITY_COMMENTS_MENTION + ) """ ) fun findCandidatesForCommentNotificationDebouncing( @@ -81,6 +104,10 @@ interface UserNotificationRepository : JpaRepository { translationId: Long, ): List + @Modifying + @Query("UPDATE UserNotification un SET un.unread = false WHERE un.recipient = ?1 AND un.id IN ?2") + fun markAsRead(recipient: UserAccount, notifications: Collection) + @Modifying @Query("UPDATE UserNotification un SET un.unread = false WHERE un.recipient = ?1") fun markAllAsRead(recipient: UserAccount) From c97c9e9aca5d4c85f69e46df92cc299cc609b1b6 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Sun, 3 Dec 2023 18:24:14 +0100 Subject: [PATCH 11/44] feat: notification preference configuration --- .../tolgee/model/NotificationPreferences.kt | 47 + .../main/kotlin/io/tolgee/model/Project.kt | 3 - .../kotlin/io/tolgee/model/UserAccount.kt | 34 +- .../io/tolgee/model/UserNotification.kt | 4 +- ...issionsNotificationPreferencesDataView.kt} | 7 +- .../NotificationPreferencesService.kt | 34 + .../notifications/UserNotificationService.kt | 8 + .../dispatchers/UserNotificationDispatch.kt | 4 +- .../NotificationPreferencesRepository.kt | 34 + .../repository/UserAccountRepository.kt | 11 +- .../repository/UserNotificationRepository.kt | 8 + .../tolgee/service/project/ProjectService.kt | 16 +- .../service/security/PermissionService.kt | 4 +- .../service/security/UserAccountService.kt | 14 +- .../main/resources/db/changelog/schema.xml | 1488 +++++++++++++++++ 15 files changed, 1674 insertions(+), 42 deletions(-) create mode 100644 backend/data/src/main/kotlin/io/tolgee/model/NotificationPreferences.kt rename backend/data/src/main/kotlin/io/tolgee/model/views/{UserAccountProjectNotificationDataView.kt => UserAccountProjectPermissionsNotificationPreferencesDataView.kt} (82%) create mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/repository/NotificationPreferencesRepository.kt diff --git a/backend/data/src/main/kotlin/io/tolgee/model/NotificationPreferences.kt b/backend/data/src/main/kotlin/io/tolgee/model/NotificationPreferences.kt new file mode 100644 index 0000000000..856ad766f6 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/model/NotificationPreferences.kt @@ -0,0 +1,47 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.model + +import com.vladmihalcea.hibernate.type.array.EnumArrayType +import io.tolgee.notifications.NotificationType +import org.hibernate.annotations.Type +import org.hibernate.annotations.TypeDef +import java.io.Serializable +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.FetchType +import javax.persistence.Id +import javax.persistence.JoinColumn +import javax.persistence.ManyToOne + +@Entity +@TypeDef(name = "enum-array", typeClass = EnumArrayType::class) +class NotificationPreferences( + @Id + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(nullable = false) + val userAccount: UserAccount, + + @Id + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(nullable = true) + val project: Project?, + + @Type(type = "enum-array") + @Column(nullable = false, columnDefinition = "varchar[]") + val disabledNotifications: Array, +) : Serializable diff --git a/backend/data/src/main/kotlin/io/tolgee/model/Project.kt b/backend/data/src/main/kotlin/io/tolgee/model/Project.kt index 02438216f3..d4b6233038 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/Project.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/Project.kt @@ -87,9 +87,6 @@ class Project( @OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, mappedBy = "project") var namespaces: MutableList = mutableListOf() - @OneToMany(fetch = FetchType.LAZY, cascade = [CascadeType.REMOVE], mappedBy = "project") - var userNotifications: MutableList = mutableListOf() - @ActivityLoggedProp override var avatarHash: String? = null diff --git a/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt b/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt index e75b0f6a34..652ae653d6 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt @@ -4,6 +4,7 @@ import com.vladmihalcea.hibernate.type.array.ListArrayType import org.hibernate.annotations.ColumnDefault import org.hibernate.annotations.Type import org.hibernate.annotations.TypeDef +import org.hibernate.annotations.Where import java.util.* import javax.persistence.CascadeType import javax.persistence.Column @@ -94,9 +95,20 @@ data class UserAccount( @ColumnDefault("true") var passwordChanged: Boolean = true - @OneToMany(fetch = FetchType.LAZY, cascade = [CascadeType.REMOVE], mappedBy = "recipient") + @OneToMany(fetch = FetchType.LAZY, cascade = [CascadeType.REMOVE], orphanRemoval = true, mappedBy = "recipient") var userNotifications: MutableList = mutableListOf() + @Where(clause = "project IS NOT NULL") + @OneToMany(fetch = FetchType.LAZY, cascade = [CascadeType.REMOVE], orphanRemoval = true, mappedBy = "userAccount") + var projectNotificationPreferences: MutableList = mutableListOf() + + @Where(clause = "project IS NULL") + @OneToMany(fetch = FetchType.LAZY, cascade = [CascadeType.REMOVE], orphanRemoval = true, mappedBy = "userAccount") + private var _globalNotificationPreferences: MutableList = mutableListOf() + + val globalNotificationPreferences: NotificationPreferences? + get() = _globalNotificationPreferences.firstOrNull() + val isDeletable: Boolean get() = this.accountType != AccountType.MANAGED && !this.isInitialUser @@ -106,26 +118,6 @@ data class UserAccount( val needsSuperJwt: Boolean get() = this.accountType != AccountType.THIRD_PARTY || isMfaEnabled - constructor( - id: Long?, - username: String?, - password: String?, - name: String?, - permissions: MutableSet, - role: Role = Role.USER, - accountType: AccountType = AccountType.LOCAL, - thirdPartyAuthType: String?, - thirdPartyAuthId: String?, - resetPasswordCode: String? - ) : this(id = 0L, username = "", password, name = "") { - this.permissions = permissions - this.role = role - this.accountType = accountType - this.thirdPartyAuthType = thirdPartyAuthType - this.thirdPartyAuthId = thirdPartyAuthId - this.resetPasswordCode = resetPasswordCode - } - enum class Role { USER, ADMIN } diff --git a/backend/data/src/main/kotlin/io/tolgee/model/UserNotification.kt b/backend/data/src/main/kotlin/io/tolgee/model/UserNotification.kt index c03748e7ba..6d93beb777 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/UserNotification.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/UserNotification.kt @@ -52,8 +52,8 @@ class UserNotification( // We most definitely need this to show the notification: eager @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(nullable = false) - val project: Project, + @JoinColumn(nullable = true) + val project: Project?, // We most definitely need this to show the notification: eager @ManyToMany(fetch = FetchType.EAGER) diff --git a/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectNotificationDataView.kt b/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionsNotificationPreferencesDataView.kt similarity index 82% rename from backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectNotificationDataView.kt rename to backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionsNotificationPreferencesDataView.kt index 741904fab4..cf7eef6129 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectNotificationDataView.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionsNotificationPreferencesDataView.kt @@ -16,11 +16,12 @@ package io.tolgee.model.views +import io.tolgee.model.NotificationPreferences import io.tolgee.model.enums.OrganizationRoleType import io.tolgee.model.enums.ProjectPermissionType import io.tolgee.model.enums.Scope -class UserAccountProjectNotificationDataView( +class UserAccountProjectPermissionsNotificationPreferencesDataView( val id: Long, val projectId: Long, val organizationRole: OrganizationRoleType?, @@ -29,6 +30,8 @@ class UserAccountProjectNotificationDataView( val permissionsBasic: ProjectPermissionType?, permissionsGranular: Array>?, permittedViewLanguages: String?, + globalNotificationPreferences: NotificationPreferences?, + projectNotificationPreferences: NotificationPreferences? ) { // My love for Hibernate have no limit 🥰🥰🥰 val basePermissionsGranular = basePermissionsGranular?.map { enumValueOf(it.name) } @@ -39,4 +42,6 @@ class UserAccountProjectNotificationDataView( .map { part -> part.toLong() } .ifEmpty { null } } + + val notificationPreferences = projectNotificationPreferences ?: globalNotificationPreferences } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt new file mode 100644 index 0000000000..50ee657789 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt @@ -0,0 +1,34 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.notifications + +import io.tolgee.repository.NotificationPreferencesRepository +import org.springframework.stereotype.Service + +@Service +class NotificationPreferencesService( + private val notificationPreferencesRepository: NotificationPreferencesRepository, +) { + + fun deleteAllByUserId(userId: Long) { + notificationPreferencesRepository.deleteAllByUserId(userId) + } + + fun deleteAllByProjectId(projectId: Long) { + notificationPreferencesRepository.deleteAllByProjectId(projectId) + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt index 0f16213104..7a19dc2e01 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt @@ -87,4 +87,12 @@ class UserNotificationService( fun markAllAsDone(user: UserAccount) { return userNotificationRepository.markAllAsDone(user) } + + fun deleteAllByUserId(userId: Long) { + userNotificationRepository.deleteAllByUserId(userId) + } + + fun deleteAllByProjectId(projectId: Long) { + userNotificationRepository.deleteAllByProjectId(projectId) + } } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt index d13f257504..103ed5dcc1 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt @@ -21,7 +21,7 @@ import io.tolgee.model.UserAccount import io.tolgee.model.activity.ActivityModifiedEntity import io.tolgee.model.enums.Scope import io.tolgee.model.translation.Translation -import io.tolgee.model.views.UserAccountProjectNotificationDataView +import io.tolgee.model.views.UserAccountProjectPermissionsNotificationPreferencesDataView import io.tolgee.notifications.NotificationType import io.tolgee.notifications.UserNotificationService import io.tolgee.notifications.dto.UserNotificationParamsDto @@ -91,7 +91,7 @@ class UserNotificationDispatch( private fun handleActivityNotificationForUser( e: NotificationCreateEvent, translationToLanguageMap: Map, - userPermissionData: UserAccountProjectNotificationDataView, + userPermissionData: UserAccountProjectPermissionsNotificationPreferencesDataView, ): UserNotificationParamsDto? { val permissions = permissionService.computeProjectPermission(userPermissionData).expandedScopes diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/NotificationPreferencesRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/NotificationPreferencesRepository.kt new file mode 100644 index 0000000000..30c33c2015 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/repository/NotificationPreferencesRepository.kt @@ -0,0 +1,34 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.repository + +import io.tolgee.model.NotificationPreferences +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Modifying +import org.springframework.data.jpa.repository.Query +import org.springframework.stereotype.Repository + +@Repository +interface NotificationPreferencesRepository : JpaRepository { + @Modifying + @Query("DELETE FROM NotificationPreferences WHERE userAccount.id = :userId") + fun deleteAllByUserId(userId: Long) + + @Modifying + @Query("DELETE FROM NotificationPreferences WHERE project.id = :projectId") + fun deleteAllByProjectId(projectId: Long) +} diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt index a8c8ee7b5a..7abe7e5878 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt @@ -2,7 +2,7 @@ package io.tolgee.repository import io.tolgee.model.UserAccount import io.tolgee.model.views.UserAccountInProjectView -import io.tolgee.model.views.UserAccountProjectNotificationDataView +import io.tolgee.model.views.UserAccountProjectPermissionsNotificationPreferencesDataView import io.tolgee.model.views.UserAccountWithOrganizationRoleView import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable @@ -165,7 +165,9 @@ interface UserAccountRepository : JpaRepository { perm_org._scopes, perm.type, perm._scopes, - array_to_string(array_agg(l.id), ',') + array_to_string(array_agg(l.id), ','), + np_global, + np_project ) FROM UserAccount ua, Project p LEFT JOIN OrganizationRole org_r ON @@ -179,6 +181,8 @@ interface UserAccountRepository : JpaRepository { org_r.organization = p.organizationOwner AND perm_org.organization = p.organizationOwner LEFT JOIN Language l ON l IN elements(perm.viewLanguages) + LEFT JOIN NotificationPreferences np_global ON np_global.userAccount = ua AND np_global.project IS NULL + LEFT JOIN NotificationPreferences np_project ON np_global.userAccount = ua AND np_global.project = p WHERE p.id = :projectId AND ua.deletedAt IS NULL AND ( @@ -188,5 +192,6 @@ interface UserAccountRepository : JpaRepository { GROUP BY ua.id, p.id, org_r.type, perm_org.type, perm_org._scopes, perm.type, perm._scopes """ ) - fun findAllPermittedUsersProjectPermissionView(projectId: Long): List + fun findAllPermittedUsersProjectPermissionNotificationPreferencesView(projectId: Long): + List } diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/UserNotificationRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/UserNotificationRepository.kt index 0c634ff7da..098862e2c1 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/UserNotificationRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/UserNotificationRepository.kt @@ -137,4 +137,12 @@ interface UserNotificationRepository : JpaRepository { @Modifying @Query("DELETE FROM user_notification WHERE marked_done_at < NOW() - INTERVAL '90 DAY'", nativeQuery = true) fun pruneOldNotifications() // Native query since HQL can't do "INTERVAL" + + @Modifying + @Query("DELETE FROM UserNotification WHERE recipient.id = :userId") + fun deleteAllByUserId(userId: Long) + + @Modifying + @Query("DELETE FROM UserNotification WHERE project.id = :projectId") + fun deleteAllByProjectId(projectId: Long) } diff --git a/backend/data/src/main/kotlin/io/tolgee/service/project/ProjectService.kt b/backend/data/src/main/kotlin/io/tolgee/service/project/ProjectService.kt index 7239087709..818cd13728 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/project/ProjectService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/project/ProjectService.kt @@ -19,6 +19,8 @@ import io.tolgee.model.Project import io.tolgee.model.UserAccount import io.tolgee.model.views.ProjectView import io.tolgee.model.views.ProjectWithLanguagesView +import io.tolgee.notifications.NotificationPreferencesService +import io.tolgee.notifications.UserNotificationService import io.tolgee.repository.ProjectRepository import io.tolgee.security.ProjectHolder import io.tolgee.security.ProjectNotSelectedException @@ -59,10 +61,10 @@ class ProjectService( private val slugGenerator: SlugGenerator, private val avatarService: AvatarService, private val activityHolder: ActivityHolder, - @Lazy - private val projectHolder: ProjectHolder, - @Lazy - private val batchJobService: BatchJobService + @Lazy private val projectHolder: ProjectHolder, + @Lazy private val batchJobService: BatchJobService, + @Lazy private val userNotificationService: UserNotificationService, + @Lazy private val notificationPreferencesService: NotificationPreferencesService, ) { @set:Autowired @set:Lazy @@ -249,11 +251,15 @@ class ProjectService( avatarService.unlinkAvatarFiles(project) batchJobService.deleteAllByProjectId(project.id) bigMetaService.deleteAllByProjectId(project.id) + + userNotificationService.deleteAllByProjectId(project.id) + notificationPreferencesService.deleteAllByProjectId(project.id) + projectRepository.delete(project) } /** - * If base language is missing on project it selects language with lowest id + * If base language is missing on project it selects the language with the lowest id * It saves updated project and returns project's new baseLanguage */ @CacheEvict(cacheNames = [Caches.PROJECTS], key = "#projectId") diff --git a/backend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.kt b/backend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.kt index 514a0ea5cc..8984f0ed86 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.kt @@ -21,7 +21,7 @@ import io.tolgee.model.UserAccount import io.tolgee.model.enums.OrganizationRoleType import io.tolgee.model.enums.ProjectPermissionType import io.tolgee.model.enums.Scope -import io.tolgee.model.views.UserAccountProjectNotificationDataView +import io.tolgee.model.views.UserAccountProjectPermissionsNotificationPreferencesDataView import io.tolgee.repository.PermissionRepository import io.tolgee.service.CachedPermissionService import io.tolgee.service.LanguageService @@ -189,7 +189,7 @@ class PermissionService( } fun computeProjectPermission( - projectPermissionDataView: UserAccountProjectNotificationDataView + projectPermissionDataView: UserAccountProjectPermissionsNotificationPreferencesDataView ): ComputedPermissionDto { val basePermissions = ComputedPermissionDto.getEmptyPermission( type = projectPermissionDataView.basePermissionsBasic, diff --git a/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt b/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt index a1ab0bb51a..51b063d619 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt @@ -19,8 +19,10 @@ import io.tolgee.exceptions.PermissionException import io.tolgee.model.UserAccount import io.tolgee.model.views.ExtendedUserAccountInProject import io.tolgee.model.views.UserAccountInProjectView -import io.tolgee.model.views.UserAccountProjectNotificationDataView +import io.tolgee.model.views.UserAccountProjectPermissionsNotificationPreferencesDataView import io.tolgee.model.views.UserAccountWithOrganizationRoleView +import io.tolgee.notifications.NotificationPreferencesService +import io.tolgee.notifications.UserNotificationService import io.tolgee.repository.UserAccountRepository import io.tolgee.service.AvatarService import io.tolgee.service.EmailVerificationService @@ -52,6 +54,8 @@ class UserAccountService( private val organizationService: OrganizationService, private val entityManager: EntityManager, private val currentDateProvider: CurrentDateProvider, + @Lazy private val userNotificationService: UserNotificationService, + @Lazy private val notificationPreferencesService: NotificationPreferencesService, ) { @Autowired lateinit var emailVerificationService: EmailVerificationService @@ -163,6 +167,10 @@ class UserAccountService( userAccount.organizationRoles.forEach { entityManager.remove(it) } + + userNotificationService.deleteAllByUserId(userAccount.id) + notificationPreferencesService.deleteAllByUserId(userAccount.id) + userAccountRepository.softDeleteUser(userAccount) applicationEventPublisher.publishEvent(OnUserCountChanged(this)) } @@ -304,8 +312,8 @@ class UserAccountService( fun getAllPermissionInformationOfPermittedUsersInProject( projectId: Long - ): List { - return userAccountRepository.findAllPermittedUsersProjectPermissionView(projectId) + ): List { + return userAccountRepository.findAllPermittedUsersProjectPermissionNotificationPreferencesView(projectId) } @Transactional diff --git a/backend/data/src/main/resources/db/changelog/schema.xml b/backend/data/src/main/resources/db/changelog/schema.xml index 2de2f6ceb7..4785e5263b 100644 --- a/backend/data/src/main/resources/db/changelog/schema.xml +++ b/backend/data/src/main/resources/db/changelog/schema.xml @@ -3011,4 +3011,1492 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 85149be092ad5522f16a8c1e172f4c6c274e8f27 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Sun, 3 Dec 2023 22:12:17 +0100 Subject: [PATCH 12/44] feat: respect notification subscription settings --- .../notifications/AbstractNotificationTest.kt | 7 +- .../RemappedNotificationsTest.kt | 12 + .../UserNotificationDebounceTest.kt | 12 + .../UserNotificationDispatchTest.kt | 12 + .../UserNotificationSubscriptionTest.kt | 68 + .../UserNotificationTranslationTest.kt | 17 +- .../testDataBuilder/TestDataService.kt | 9 +- .../NotificationPreferencesBuilder.kt | 11 + .../builders/UserAccountBuilder.kt | 5 + .../data/NotificationSubscriptionTestData.kt | 107 ++ .../kotlin/io/tolgee/model/UserAccount.kt | 2 + .../NotificationPreferences.kt | 50 +- .../{ => notifications}/UserNotification.kt | 4 +- ...missionsNotificationPreferencesDataView.kt | 2 +- .../NotificationPreferencesService.kt | 2 +- .../UserNotificationDebouncer.kt | 4 +- .../notifications/UserNotificationService.kt | 4 +- .../dispatchers/UserNotificationDispatch.kt | 14 +- .../dto/NotificationCreateDto.kt | 2 +- .../events/UserNotificationPushEvent.kt | 2 +- .../repository/UserAccountRepository.kt | 8 +- .../NotificationPreferencesRepository.kt | 4 +- .../UserNotificationRepository.kt | 4 +- .../service/security/UserAccountService.kt | 8 +- .../main/resources/db/changelog/schema.xml | 1503 +---------------- .../kotlin/io/tolgee/testing/satisfies.kt | 4 +- 26 files changed, 349 insertions(+), 1528 deletions(-) create mode 100644 backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationSubscriptionTest.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/NotificationPreferencesBuilder.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationSubscriptionTestData.kt rename backend/data/src/main/kotlin/io/tolgee/model/{ => notifications}/NotificationPreferences.kt (56%) rename backend/data/src/main/kotlin/io/tolgee/model/{ => notifications}/UserNotification.kt (96%) rename backend/data/src/main/kotlin/io/tolgee/repository/{ => notifications}/NotificationPreferencesRepository.kt (92%) rename backend/data/src/main/kotlin/io/tolgee/repository/{ => notifications}/UserNotificationRepository.kt (98%) diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt index 52ca7d38de..1eb68e4c12 100644 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt @@ -16,8 +16,7 @@ package io.tolgee.notifications -import io.tolgee.development.testDataBuilder.data.NotificationsTestData -import io.tolgee.repository.UserNotificationRepository +import io.tolgee.repository.notifications.UserNotificationRepository import io.tolgee.testing.AuthorizedControllerTest import io.tolgee.testing.assert import io.tolgee.util.addMilliseconds @@ -43,15 +42,11 @@ abstract class AbstractNotificationTest : AuthorizedControllerTest() { @SpyBean @Autowired lateinit var userNotificationRepository: UserNotificationRepository - lateinit var testData: NotificationsTestData lateinit var semaphore: Semaphore @BeforeEach fun setupTests() { - testData = NotificationsTestData() - testDataService.saveTestData(testData.root) - semaphore = Semaphore(0) doAnswer { diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/RemappedNotificationsTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/RemappedNotificationsTest.kt index 5cf19713e9..b00b503e18 100644 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/RemappedNotificationsTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/RemappedNotificationsTest.kt @@ -16,6 +16,7 @@ package io.tolgee.notifications +import io.tolgee.development.testDataBuilder.data.NotificationsTestData import io.tolgee.dtos.request.key.ComplexEditKeyDto import io.tolgee.dtos.request.key.KeyScreenshotDto import io.tolgee.fixtures.andGetContentAsJsonMap @@ -23,10 +24,21 @@ import io.tolgee.fixtures.andIsCreated import io.tolgee.fixtures.andIsOk import io.tolgee.testing.assert import io.tolgee.util.generateImage +import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.springframework.mock.web.MockMultipartFile class RemappedNotificationsTest : AbstractNotificationTest() { + lateinit var testData: NotificationsTestData + + @BeforeEach + override fun setupTests() { + testData = NotificationsTestData() + testDataService.saveTestData(testData.root) + + super.setupTests() + } + @Test fun `it does properly remap imports to key and translation notifications`() { performAuthMultipart( diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt index f8cefd8f10..4f85e24846 100644 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt @@ -16,15 +16,27 @@ package io.tolgee.notifications +import io.tolgee.development.testDataBuilder.data.NotificationsTestData import io.tolgee.dtos.request.key.CreateKeyDto import io.tolgee.dtos.request.translation.SetTranslationsWithKeyDto import io.tolgee.dtos.request.translation.comment.TranslationCommentWithLangKeyDto import io.tolgee.fixtures.andIsCreated import io.tolgee.fixtures.andIsOk import io.tolgee.testing.assert +import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test class UserNotificationDebounceTest : AbstractNotificationTest() { + lateinit var testData: NotificationsTestData + + @BeforeEach + override fun setupTests() { + testData = NotificationsTestData() + testDataService.saveTestData(testData.root) + + super.setupTests() + } + @Test fun `it debounces notifications of the same type`() { performAuthPost( diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDispatchTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDispatchTest.kt index 3e6e391b18..506e49c30a 100644 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDispatchTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDispatchTest.kt @@ -16,16 +16,28 @@ package io.tolgee.notifications +import io.tolgee.development.testDataBuilder.data.NotificationsTestData import io.tolgee.dtos.request.key.CreateKeyDto import io.tolgee.dtos.request.translation.SetTranslationsWithKeyDto import io.tolgee.fixtures.andIsCreated import io.tolgee.fixtures.andIsOk import io.tolgee.testing.assert import io.tolgee.util.generateImage +import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.springframework.mock.web.MockMultipartFile class UserNotificationDispatchTest : AbstractNotificationTest() { + lateinit var testData: NotificationsTestData + + @BeforeEach + override fun setupTests() { + testData = NotificationsTestData() + testDataService.saveTestData(testData.root) + + super.setupTests() + } + @Test fun `it dispatches notifications to everyone in project`() { performAuthPost( diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationSubscriptionTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationSubscriptionTest.kt new file mode 100644 index 0000000000..669ecdcf6f --- /dev/null +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationSubscriptionTest.kt @@ -0,0 +1,68 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.notifications + +import io.tolgee.development.testDataBuilder.data.NotificationSubscriptionTestData +import io.tolgee.dtos.request.key.CreateKeyDto +import io.tolgee.fixtures.andIsCreated +import io.tolgee.testing.assert +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test + +class UserNotificationSubscriptionTest : AbstractNotificationTest() { + lateinit var testData: NotificationSubscriptionTestData + + @BeforeEach + override fun setupTests() { + testData = NotificationSubscriptionTestData() + testDataService.saveTestData(testData.root) + + super.setupTests() + } + + @Test + fun `it respects global notification subscription settings`() { + performAuthPost( + "/v2/projects/${testData.project1.id}/keys/create", + CreateKeyDto(name = "test-key") + ).andIsCreated + + waitUntilUserNotificationDispatch(1) + val notifications1 = userNotificationRepository.findAllByRecipient(testData.user1) + val notifications2 = userNotificationRepository.findAllByRecipient(testData.user2) + + notifications1.assert.hasSize(1) + notifications2.assert.hasSize(0) + ensureNoUserNotificationDispatch() + } + + @Test + fun `it respects project-level notification subscription settings`() { + performAuthPost( + "/v2/projects/${testData.project2.id}/keys/create", + CreateKeyDto(name = "test-key") + ).andIsCreated + + waitUntilUserNotificationDispatch(1) + val notifications1 = userNotificationRepository.findAllByRecipient(testData.user1) + val notifications2 = userNotificationRepository.findAllByRecipient(testData.user2) + + notifications1.assert.hasSize(0) + notifications2.assert.hasSize(1) + ensureNoUserNotificationDispatch() + } +} diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationTranslationTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationTranslationTest.kt index e55756babd..85e133137c 100644 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationTranslationTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationTranslationTest.kt @@ -16,14 +16,26 @@ package io.tolgee.notifications +import io.tolgee.development.testDataBuilder.data.NotificationsTestData import io.tolgee.dtos.request.key.CreateKeyDto import io.tolgee.dtos.request.translation.SetTranslationsWithKeyDto import io.tolgee.fixtures.andIsCreated import io.tolgee.fixtures.andIsOk import io.tolgee.testing.assert +import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test class UserNotificationTranslationTest : AbstractNotificationTest() { + lateinit var testData: NotificationsTestData + + @BeforeEach + override fun setupTests() { + testData = NotificationsTestData() + testDataService.saveTestData(testData.root) + + super.setupTests() + } + @Test fun `it does not dispatch the same type of notification for source strings and translated strings`() { performAuthPut( @@ -92,9 +104,6 @@ class UserNotificationTranslationTest : AbstractNotificationTest() { userNotificationRepository.findAllByRecipient(testData.alice).assert .noneMatch { it.type == NotificationType.ACTIVITY_TRANSLATION_OUTDATED } - .satisfiesOnlyOnce { - it.type.assert.isEqualTo(NotificationType.ACTIVITY_TRANSLATIONS_UPDATED) - it.modifiedEntities.assert.noneSatisfy { e -> e.modifications.assert.hasOnlyFields("outdated") } - } + .noneMatch { it.type == NotificationType.ACTIVITY_TRANSLATIONS_UPDATED } } } diff --git a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/TestDataService.kt b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/TestDataService.kt index dfe1952f60..e512c691aa 100644 --- a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/TestDataService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/TestDataService.kt @@ -76,7 +76,6 @@ class TestDataService( private val automationService: AutomationService, private val contentDeliveryConfigService: ContentDeliveryConfigService ) : Logging { - @Transactional fun saveTestData(ft: TestDataBuilder.() -> Unit): TestDataBuilder { val builder = TestDataBuilder() @@ -108,6 +107,14 @@ class TestDataService( executeInNewTransaction(transactionManager) { saveProjectData(builder) + + // These depend on users and projects, so they must be stored only after all the projects have been stored. + builder.data.userAccounts.forEach { + it.data.notificationPreferences.forEach { entityBuilder -> + entityManager.persist(entityBuilder.self) + } + } + finalize() } diff --git a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/NotificationPreferencesBuilder.kt b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/NotificationPreferencesBuilder.kt new file mode 100644 index 0000000000..a1146d581d --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/NotificationPreferencesBuilder.kt @@ -0,0 +1,11 @@ +package io.tolgee.development.testDataBuilder.builders + +import io.tolgee.development.testDataBuilder.EntityDataBuilder +import io.tolgee.model.notifications.NotificationPreferences + +class NotificationPreferencesBuilder( + val userAccountBuilder: UserAccountBuilder +) : EntityDataBuilder { + override var self: NotificationPreferences = + NotificationPreferences(userAccountBuilder.self, null, emptyArray()) +} diff --git a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/UserAccountBuilder.kt b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/UserAccountBuilder.kt index ebf87e7aef..1da12f11f1 100644 --- a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/UserAccountBuilder.kt +++ b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/UserAccountBuilder.kt @@ -4,6 +4,7 @@ import io.tolgee.development.testDataBuilder.FT import io.tolgee.model.Pat import io.tolgee.model.UserAccount import io.tolgee.model.UserPreferences +import io.tolgee.model.notifications.NotificationPreferences import org.springframework.core.io.ClassPathResource class UserAccountBuilder( @@ -17,6 +18,7 @@ class UserAccountBuilder( var avatarFile: ClassPathResource? = null var userPreferences: UserPreferencesBuilder? = null var pats: MutableList = mutableListOf() + var notificationPreferences: MutableList = mutableListOf() } var data = DATA() @@ -31,4 +33,7 @@ class UserAccountBuilder( } fun addPat(ft: FT) = addOperation(data.pats, ft) + + fun addNotificationPreferences(ft: FT) = + addOperation(data.notificationPreferences, ft) } diff --git a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationSubscriptionTestData.kt b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationSubscriptionTestData.kt new file mode 100644 index 0000000000..88e057ea6b --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationSubscriptionTestData.kt @@ -0,0 +1,107 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.development.testDataBuilder.data + +import io.tolgee.development.testDataBuilder.builders.TestDataBuilder +import io.tolgee.model.Organization +import io.tolgee.model.Project +import io.tolgee.model.UserAccount +import io.tolgee.model.enums.OrganizationRoleType +import io.tolgee.notifications.NotificationType + +class NotificationSubscriptionTestData { + lateinit var user1: UserAccount + lateinit var user2: UserAccount + + lateinit var organization: Organization + + lateinit var project1: Project + lateinit var project2: Project + + val root: TestDataBuilder = TestDataBuilder() + + init { + root.apply { + addUserAccount { + username = "admin" + role = UserAccount.Role.ADMIN + } + + val user1Builder = addUserAccountWithoutOrganization { + name = "User 1" + username = "user1" + user1 = this + } + + val user2Builder = addUserAccountWithoutOrganization { + name = "User 2" + username = "user2" + user2 = this + } + + addOrganization { + name = "Test org" + slug = "test-org" + + organization = this + + addProject { + name = "Test project 1" + slug = "project1" + organizationOwner = organization + + project1 = this + } + + addProject { + name = "Test project 2" + slug = "project2" + organizationOwner = organization + + project2 = this + } + }.build { + addRole { + user = user1 + type = OrganizationRoleType.OWNER + } + + addRole { + user = user2 + type = OrganizationRoleType.OWNER + } + } + + user1Builder.build { + addNotificationPreferences { + project = project2 + disabledNotifications = arrayOf(NotificationType.ACTIVITY_KEYS_CREATED) + } + } + + user2Builder.build { + addNotificationPreferences { + disabledNotifications = arrayOf(NotificationType.ACTIVITY_KEYS_CREATED) + } + + addNotificationPreferences { + project = project2 + } + } + } + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt b/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt index 652ae653d6..cefde3bbe0 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt @@ -1,6 +1,8 @@ package io.tolgee.model import com.vladmihalcea.hibernate.type.array.ListArrayType +import io.tolgee.model.notifications.NotificationPreferences +import io.tolgee.model.notifications.UserNotification import org.hibernate.annotations.ColumnDefault import org.hibernate.annotations.Type import org.hibernate.annotations.TypeDef diff --git a/backend/data/src/main/kotlin/io/tolgee/model/NotificationPreferences.kt b/backend/data/src/main/kotlin/io/tolgee/model/notifications/NotificationPreferences.kt similarity index 56% rename from backend/data/src/main/kotlin/io/tolgee/model/NotificationPreferences.kt rename to backend/data/src/main/kotlin/io/tolgee/model/notifications/NotificationPreferences.kt index 856ad766f6..87054b17fa 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/NotificationPreferences.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/notifications/NotificationPreferences.kt @@ -14,34 +14,68 @@ * limitations under the License. */ -package io.tolgee.model +package io.tolgee.model.notifications import com.vladmihalcea.hibernate.type.array.EnumArrayType +import io.tolgee.model.Project +import io.tolgee.model.UserAccount import io.tolgee.notifications.NotificationType +import org.hibernate.annotations.Parameter import org.hibernate.annotations.Type import org.hibernate.annotations.TypeDef -import java.io.Serializable import javax.persistence.Column import javax.persistence.Entity import javax.persistence.FetchType +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType import javax.persistence.Id +import javax.persistence.Index import javax.persistence.JoinColumn import javax.persistence.ManyToOne +import javax.persistence.Table @Entity -@TypeDef(name = "enum-array", typeClass = EnumArrayType::class) +@TypeDef( + name = "enum-array", + typeClass = EnumArrayType::class, + parameters = [ + Parameter( + name = EnumArrayType.SQL_ARRAY_TYPE, + value = "varchar" + ) + ] +) +@Table( + indexes = [ + Index( + name = "notification_preferences_user_project", + columnList = "user_account_id, project_id", + unique = true, + ), + Index( + name = "notification_preferences_user", + columnList = "user_account_id" + ), + Index( + name = "notification_preferences_project", + columnList = "project_id", + ) + ] +) class NotificationPreferences( - @Id @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(nullable = false) val userAccount: UserAccount, - @Id @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(nullable = true) - val project: Project?, + var project: Project?, @Type(type = "enum-array") @Column(nullable = false, columnDefinition = "varchar[]") - val disabledNotifications: Array, -) : Serializable + var disabledNotifications: Array, +) { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + val id: Long = 0L +} diff --git a/backend/data/src/main/kotlin/io/tolgee/model/UserNotification.kt b/backend/data/src/main/kotlin/io/tolgee/model/notifications/UserNotification.kt similarity index 96% rename from backend/data/src/main/kotlin/io/tolgee/model/UserNotification.kt rename to backend/data/src/main/kotlin/io/tolgee/model/notifications/UserNotification.kt index 6d93beb777..f5614b148f 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/UserNotification.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/notifications/UserNotification.kt @@ -14,8 +14,10 @@ * limitations under the License. */ -package io.tolgee.model +package io.tolgee.model.notifications +import io.tolgee.model.Project +import io.tolgee.model.UserAccount import io.tolgee.model.activity.ActivityModifiedEntity import io.tolgee.model.batch.BatchJob import io.tolgee.notifications.NotificationType diff --git a/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionsNotificationPreferencesDataView.kt b/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionsNotificationPreferencesDataView.kt index cf7eef6129..d326fd5366 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionsNotificationPreferencesDataView.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionsNotificationPreferencesDataView.kt @@ -16,10 +16,10 @@ package io.tolgee.model.views -import io.tolgee.model.NotificationPreferences import io.tolgee.model.enums.OrganizationRoleType import io.tolgee.model.enums.ProjectPermissionType import io.tolgee.model.enums.Scope +import io.tolgee.model.notifications.NotificationPreferences class UserAccountProjectPermissionsNotificationPreferencesDataView( val id: Long, diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt index 50ee657789..27144a35f1 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt @@ -16,7 +16,7 @@ package io.tolgee.notifications -import io.tolgee.repository.NotificationPreferencesRepository +import io.tolgee.repository.notifications.NotificationPreferencesRepository import org.springframework.stereotype.Service @Service diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationDebouncer.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationDebouncer.kt index 1bddd262ce..5bf60d2087 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationDebouncer.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationDebouncer.kt @@ -18,13 +18,13 @@ package io.tolgee.notifications import io.tolgee.model.Project import io.tolgee.model.UserAccount -import io.tolgee.model.UserNotification import io.tolgee.model.activity.ActivityModifiedEntity +import io.tolgee.model.notifications.UserNotification import io.tolgee.model.translation.Translation import io.tolgee.model.translation.TranslationComment import io.tolgee.notifications.dto.NotificationCreateDto import io.tolgee.notifications.dto.UserNotificationParamsDto -import io.tolgee.repository.UserNotificationRepository +import io.tolgee.repository.notifications.UserNotificationRepository import org.springframework.stereotype.Component import java.util.* diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt index 7a19dc2e01..49c8a40a8a 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt @@ -17,11 +17,11 @@ package io.tolgee.notifications import io.tolgee.model.UserAccount -import io.tolgee.model.UserNotification +import io.tolgee.model.notifications.UserNotification import io.tolgee.notifications.dto.NotificationCreateDto import io.tolgee.notifications.dto.UserNotificationParamsDto import io.tolgee.notifications.events.UserNotificationPushEvent -import io.tolgee.repository.UserNotificationRepository +import io.tolgee.repository.notifications.UserNotificationRepository import org.springframework.context.ApplicationEventPublisher import org.springframework.data.domain.Pageable import org.springframework.stereotype.Service diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt index 103ed5dcc1..551d882b5e 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt @@ -61,16 +61,22 @@ class UserNotificationDispatch( private fun handleActivityNotification(e: NotificationCreateEvent) { val users = userAccountService.getAllPermissionInformationOfPermittedUsersInProject(e.notification.project.id) + .filter { + println(it.notificationPreferences?.userAccount?.id) + println(it.notificationPreferences?.project?.id) + println(it.notificationPreferences?.disabledNotifications) + println("--") + it.notificationPreferences?.disabledNotifications?.contains(e.notification.type) != true && + it.id != e.responsibleUser?.id + } + val translationToLanguageMap = e.notification.modifiedEntities!! .filter { it.entityClass == Translation::class.simpleName } .map { it.entityId } .let { if (it.isEmpty()) emptyMap() else languageService.findLanguageIdsOfTranslations(it) } val notifications = users.mapNotNull { - if (it.id != e.responsibleUser?.id) - handleActivityNotificationForUser(e, translationToLanguageMap, it) - else - null + handleActivityNotificationForUser(e, translationToLanguageMap, it) } userNotificationService.dispatchNotifications(e.notification, notifications) diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt index da5b898dcb..a5f6bbaed3 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt @@ -17,9 +17,9 @@ package io.tolgee.notifications.dto import io.tolgee.model.Project -import io.tolgee.model.UserNotification import io.tolgee.model.activity.ActivityModifiedEntity import io.tolgee.model.batch.BatchJob +import io.tolgee.model.notifications.UserNotification import io.tolgee.notifications.NotificationType data class NotificationCreateDto( diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/events/UserNotificationPushEvent.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/events/UserNotificationPushEvent.kt index d1052e802e..2e416245ad 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/events/UserNotificationPushEvent.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/events/UserNotificationPushEvent.kt @@ -16,7 +16,7 @@ package io.tolgee.notifications.events -import io.tolgee.model.UserNotification +import io.tolgee.model.notifications.UserNotification /** * Event sent when a set of users received a new notification. diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt index 7abe7e5878..4b2d203902 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt @@ -157,7 +157,7 @@ interface UserAccountRepository : JpaRepository { @Query( """ - SELECT new io.tolgee.model.views.UserAccountProjectNotificationDataView( + SELECT new io.tolgee.model.views.UserAccountProjectPermissionsNotificationPreferencesDataView( ua.id, p.id, org_r.type, @@ -181,15 +181,15 @@ interface UserAccountRepository : JpaRepository { org_r.organization = p.organizationOwner AND perm_org.organization = p.organizationOwner LEFT JOIN Language l ON l IN elements(perm.viewLanguages) - LEFT JOIN NotificationPreferences np_global ON np_global.userAccount = ua AND np_global.project IS NULL - LEFT JOIN NotificationPreferences np_project ON np_global.userAccount = ua AND np_global.project = p + LEFT JOIN FETCH NotificationPreferences np_global ON np_global.userAccount = ua AND np_global.project IS NULL + LEFT JOIN FETCH NotificationPreferences np_project ON np_project.userAccount = ua AND np_project.project = p WHERE p.id = :projectId AND ua.deletedAt IS NULL AND ( (perm._scopes IS NOT NULL AND perm._scopes != '{}') OR perm.type IS NOT NULL OR (perm_org._scopes IS NOT NULL AND perm_org._scopes != '{}') OR perm_org.type IS NOT NULL ) - GROUP BY ua.id, p.id, org_r.type, perm_org.type, perm_org._scopes, perm.type, perm._scopes + GROUP BY ua.id, p.id, org_r.type, perm_org.type, perm_org._scopes, perm.type, perm._scopes, np_global, np_project """ ) fun findAllPermittedUsersProjectPermissionNotificationPreferencesView(projectId: Long): diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/NotificationPreferencesRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/notifications/NotificationPreferencesRepository.kt similarity index 92% rename from backend/data/src/main/kotlin/io/tolgee/repository/NotificationPreferencesRepository.kt rename to backend/data/src/main/kotlin/io/tolgee/repository/notifications/NotificationPreferencesRepository.kt index 30c33c2015..536131c07d 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/NotificationPreferencesRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/notifications/NotificationPreferencesRepository.kt @@ -14,9 +14,9 @@ * limitations under the License. */ -package io.tolgee.repository +package io.tolgee.repository.notifications -import io.tolgee.model.NotificationPreferences +import io.tolgee.model.notifications.NotificationPreferences import org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.Modifying import org.springframework.data.jpa.repository.Query diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/UserNotificationRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt similarity index 98% rename from backend/data/src/main/kotlin/io/tolgee/repository/UserNotificationRepository.kt rename to backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt index 098862e2c1..f702973c4e 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/UserNotificationRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt @@ -14,11 +14,11 @@ * limitations under the License. */ -package io.tolgee.repository +package io.tolgee.repository.notifications import io.tolgee.model.Project import io.tolgee.model.UserAccount -import io.tolgee.model.UserNotification +import io.tolgee.model.notifications.UserNotification import io.tolgee.notifications.NotificationType import org.springframework.data.domain.Pageable import org.springframework.data.jpa.repository.JpaRepository diff --git a/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt b/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt index 51b063d619..059d13f529 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt @@ -310,9 +310,8 @@ class UserAccountService( } } - fun getAllPermissionInformationOfPermittedUsersInProject( - projectId: Long - ): List { + fun getAllPermissionInformationOfPermittedUsersInProject(projectId: Long): + List { return userAccountRepository.findAllPermittedUsersProjectPermissionNotificationPreferencesView(projectId) } @@ -427,9 +426,6 @@ class UserAccountService( this.applicationEventPublisher.publishEvent(OnUserCountChanged(this)) } - val isAnyUserAccount: Boolean - get() = userAccountRepository.count() > 0 - private fun transferLegacyNoAuthUser() { val legacyImplicitUser = findActive("___implicit_user") ?: return diff --git a/backend/data/src/main/resources/db/changelog/schema.xml b/backend/data/src/main/resources/db/changelog/schema.xml index 4785e5263b..00113a279f 100644 --- a/backend/data/src/main/resources/db/changelog/schema.xml +++ b/backend/data/src/main/resources/db/changelog/schema.xml @@ -2955,1102 +2955,24 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - + - - - - - + - - - - + + - - - - - - - - + @@ -4070,7 +2992,7 @@ - + @@ -4086,417 +3008,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - + + - - - + + + - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - + - - - diff --git a/backend/testing/src/main/kotlin/io/tolgee/testing/satisfies.kt b/backend/testing/src/main/kotlin/io/tolgee/testing/satisfies.kt index a39ab32b90..a56414eb6b 100644 --- a/backend/testing/src/main/kotlin/io/tolgee/testing/satisfies.kt +++ b/backend/testing/src/main/kotlin/io/tolgee/testing/satisfies.kt @@ -21,11 +21,11 @@ import org.assertj.core.api.Condition import org.assertj.core.api.ThrowingConsumer // https://github.com/assertj/assertj/issues/2357 -fun , E> AbstractAssert.satisfies(fn: (actual: E) -> Unit): S { +fun , E> AbstractAssert.satisfies(fn: (actual: E) -> Unit): S { return satisfies(ThrowingConsumer { fn(it) }) } -fun , E> AbstractAssert.satisfiesIf(fn: (actual: E) -> Boolean): S { +fun , E> AbstractAssert.satisfiesIf(fn: (actual: E) -> Boolean): S { return satisfies(object : Condition() { override fun matches(value: E): Boolean = fn(value) }) From f235131eb840b2a0a48ead9a61134f6bc5ec36c9 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Mon, 4 Dec 2023 11:35:48 +0100 Subject: [PATCH 13/44] tests: fix json number matching --- .../V2ProjectsControllerTest.kt | 47 +++++++++++-------- .../io/tolgee/fixtures/statusExpectations.kt | 13 ++++- 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/V2ProjectsControllerTest.kt b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/V2ProjectsControllerTest.kt index d4c0efacc2..26f6b7aa15 100644 --- a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/V2ProjectsControllerTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/V2ProjectsControllerTest.kt @@ -3,7 +3,14 @@ package io.tolgee.api.v2.controllers.v2ProjectsController import io.tolgee.ProjectAuthControllerTest import io.tolgee.development.testDataBuilder.data.BaseTestData import io.tolgee.development.testDataBuilder.data.ProjectsTestData -import io.tolgee.fixtures.* +import io.tolgee.fixtures.andAssertThatJson +import io.tolgee.fixtures.andIsBadRequest +import io.tolgee.fixtures.andIsNotFound +import io.tolgee.fixtures.andIsOk +import io.tolgee.fixtures.andPrettyPrint +import io.tolgee.fixtures.generateUniqueString +import io.tolgee.fixtures.isPermissionScopes +import io.tolgee.fixtures.node import io.tolgee.model.Permission import io.tolgee.model.UserAccount import io.tolgee.model.enums.ProjectPermissionType @@ -75,24 +82,26 @@ open class V2ProjectsControllerTest : ProjectAuthControllerTest("/v2/projects/") node("[0].organizationOwner.name").isEqualTo("test_username") node("[0].directPermission.scopes").isPermissionScopes(ProjectPermissionType.MANAGE) node("[0].computedPermission.scopes").isPermissionScopes(ProjectPermissionType.MANAGE) - node("[0].stats.translationStatePercentages").isEqualTo( - """ - { - "UNTRANSLATED": 100.0, - "TRANSLATED": 0, - "REVIEWED": 0 - } - """ - ) - node("[1].stats.translationStatePercentages").isEqualTo( - """ - { - "UNTRANSLATED": 25.0, - "TRANSLATED": 75.0, - "REVIEWED": 0.0 - } - """ - ) + node("[0].stats.translationStatePercentages") + .isEqualTo( + """ + { + "UNTRANSLATED": 100.0, + "TRANSLATED": 0, + "REVIEWED": 0 + } + """ + ) + node("[1].stats.translationStatePercentages") + .isEqualTo( + """ + { + "UNTRANSLATED": 25.0, + "TRANSLATED": 75.0, + "REVIEWED": 0 + } + """ + ) } } } diff --git a/backend/testing/src/main/kotlin/io/tolgee/fixtures/statusExpectations.kt b/backend/testing/src/main/kotlin/io/tolgee/fixtures/statusExpectations.kt index 0c88300a8d..7d37969374 100644 --- a/backend/testing/src/main/kotlin/io/tolgee/fixtures/statusExpectations.kt +++ b/backend/testing/src/main/kotlin/io/tolgee/fixtures/statusExpectations.kt @@ -58,7 +58,18 @@ val ResultActions.andAssertThatJson: JsonAssert.ConfigurableJsonAssert fun ResultActions.andAssertThatJson(jsonAssert: JsonAssert.ConfigurableJsonAssert.() -> Unit): ResultActions { tryPrettyPrinting { - jsonAssert(assertThatJson(this.andGetContentAsString)) + jsonAssert( + assertThatJson(this.andGetContentAsString) + // https://github.com/lukas-krecan/JsonUnit?tab=readme-ov-file#numerical-comparison + // We only care about the numeric value, not the precision. Not the business of doing physics (...yet)! :p + .withConfiguration { + it.withNumberComparator { a, b, tolerance -> + val diff = if (a > b) a - b else b - a + diff <= (tolerance ?: BigDecimal.ZERO) + } + } + ) + this } return this From caa4ce4df0d7c8bb04e026a3968ed8657b9ea771 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Mon, 4 Dec 2023 11:36:40 +0100 Subject: [PATCH 14/44] fix: handle modified entity relations using rdbms-level cascade --- backend/data/src/main/kotlin/io/tolgee/model/Permission.kt | 1 - backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt | 4 ++-- .../notifications/dispatchers/UserNotificationDispatch.kt | 4 ---- backend/data/src/main/resources/db/changelog/schema.xml | 2 +- 4 files changed, 3 insertions(+), 8 deletions(-) diff --git a/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt b/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt index e8c15f965e..7e0aa3cacd 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt @@ -94,7 +94,6 @@ class Permission( * When specified, user is restricted to edit specific language translations. */ @ManyToMany(fetch = FetchType.EAGER) - @JoinTable(name = "permission_view_languages") var viewLanguages: MutableSet = mutableSetOf() /** diff --git a/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt b/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt index cefde3bbe0..40be16d379 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt @@ -100,11 +100,11 @@ data class UserAccount( @OneToMany(fetch = FetchType.LAZY, cascade = [CascadeType.REMOVE], orphanRemoval = true, mappedBy = "recipient") var userNotifications: MutableList = mutableListOf() - @Where(clause = "project IS NOT NULL") + @Where(clause = "project_id IS NOT NULL") @OneToMany(fetch = FetchType.LAZY, cascade = [CascadeType.REMOVE], orphanRemoval = true, mappedBy = "userAccount") var projectNotificationPreferences: MutableList = mutableListOf() - @Where(clause = "project IS NULL") + @Where(clause = "project_id IS NULL") @OneToMany(fetch = FetchType.LAZY, cascade = [CascadeType.REMOVE], orphanRemoval = true, mappedBy = "userAccount") private var _globalNotificationPreferences: MutableList = mutableListOf() diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt index 551d882b5e..8ddd86a117 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt @@ -62,10 +62,6 @@ class UserNotificationDispatch( private fun handleActivityNotification(e: NotificationCreateEvent) { val users = userAccountService.getAllPermissionInformationOfPermittedUsersInProject(e.notification.project.id) .filter { - println(it.notificationPreferences?.userAccount?.id) - println(it.notificationPreferences?.project?.id) - println(it.notificationPreferences?.disabledNotifications) - println("--") it.notificationPreferences?.disabledNotifications?.contains(e.notification.type) != true && it.id != e.responsibleUser?.id } diff --git a/backend/data/src/main/resources/db/changelog/schema.xml b/backend/data/src/main/resources/db/changelog/schema.xml index 00113a279f..ed491cc1a5 100644 --- a/backend/data/src/main/resources/db/changelog/schema.xml +++ b/backend/data/src/main/resources/db/changelog/schema.xml @@ -3025,7 +3025,7 @@ - + From 2384df955f514e9505906f36045a728bac541229 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Mon, 4 Dec 2023 11:39:44 +0100 Subject: [PATCH 15/44] chore: lint --- .../io/tolgee/fixtures/statusExpectations.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/backend/testing/src/main/kotlin/io/tolgee/fixtures/statusExpectations.kt b/backend/testing/src/main/kotlin/io/tolgee/fixtures/statusExpectations.kt index 7d37969374..ed74c25a9a 100644 --- a/backend/testing/src/main/kotlin/io/tolgee/fixtures/statusExpectations.kt +++ b/backend/testing/src/main/kotlin/io/tolgee/fixtures/statusExpectations.kt @@ -60,14 +60,14 @@ fun ResultActions.andAssertThatJson(jsonAssert: JsonAssert.ConfigurableJsonAsser tryPrettyPrinting { jsonAssert( assertThatJson(this.andGetContentAsString) - // https://github.com/lukas-krecan/JsonUnit?tab=readme-ov-file#numerical-comparison - // We only care about the numeric value, not the precision. Not the business of doing physics (...yet)! :p - .withConfiguration { - it.withNumberComparator { a, b, tolerance -> - val diff = if (a > b) a - b else b - a - diff <= (tolerance ?: BigDecimal.ZERO) + // https://github.com/lukas-krecan/JsonUnit?tab=readme-ov-file#numerical-comparison + // We only care about the numeric value, not the precision. Not the business of doing physics (...yet)! :p + .withConfiguration { + it.withNumberComparator { a, b, tolerance -> + val diff = if (a > b) a - b else b - a + diff <= (tolerance ?: BigDecimal.ZERO) + } } - } ) this From be30fc9feb854dd961ed9037757014c80ada3b98 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Mon, 4 Dec 2023 12:32:44 +0100 Subject: [PATCH 16/44] fix: hibernate proxy behavior --- .../io/tolgee/batch/AbstractBatchJobsGeneralTest.kt | 7 +++++++ .../notifications/UserNotificationDebounceTest.kt | 13 +++++++------ .../kotlin/io/tolgee/model/DismissedAnnouncement.kt | 11 ++++++++++- .../kotlin/io/tolgee/model/EmailVerification.kt | 2 ++ .../kotlin/io/tolgee/model/ForcedServerDateTime.kt | 2 ++ .../src/main/kotlin/io/tolgee/model/Invitation.kt | 2 ++ .../src/main/kotlin/io/tolgee/model/Organization.kt | 5 ++++- .../src/main/kotlin/io/tolgee/model/Permission.kt | 2 ++ .../data/src/main/kotlin/io/tolgee/model/Project.kt | 2 ++ .../kotlin/io/tolgee/model/StandardAuditModel.kt | 2 ++ .../src/main/kotlin/io/tolgee/model/UserAccount.kt | 2 ++ .../main/kotlin/io/tolgee/model/UserPreferences.kt | 2 ++ .../model/activity/ActivityDescribingEntity.kt | 4 ++++ .../io/tolgee/model/activity/ActivityRevision.kt | 2 ++ .../contentDelivery/AzureContentStorageConfig.kt | 2 ++ .../model/contentDelivery/S3ContentStorageConfig.kt | 4 +++- .../model/notifications/NotificationPreferences.kt | 2 ++ .../tolgee/model/notifications/UserNotification.kt | 2 ++ .../notifications/UserNotificationRepository.kt | 4 +--- 19 files changed, 60 insertions(+), 12 deletions(-) diff --git a/backend/app/src/test/kotlin/io/tolgee/batch/AbstractBatchJobsGeneralTest.kt b/backend/app/src/test/kotlin/io/tolgee/batch/AbstractBatchJobsGeneralTest.kt index 4f306a9ae1..3d03370a2b 100644 --- a/backend/app/src/test/kotlin/io/tolgee/batch/AbstractBatchJobsGeneralTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/batch/AbstractBatchJobsGeneralTest.kt @@ -7,6 +7,7 @@ import io.tolgee.batch.processors.PreTranslationByTmChunkProcessor import io.tolgee.constants.Message import io.tolgee.development.testDataBuilder.data.BatchJobsTestData import io.tolgee.model.batch.BatchJobStatus +import io.tolgee.notifications.listeners.ActivityEventListener import io.tolgee.testing.WebsocketTest import io.tolgee.testing.assert import io.tolgee.util.Logging @@ -15,6 +16,7 @@ import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.mockito.Mockito import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.mock.mockito.MockBean import org.springframework.boot.test.mock.mockito.SpyBean import java.time.Duration import java.util.* @@ -61,6 +63,11 @@ abstract class AbstractBatchJobsGeneralTest : AbstractSpringTest(), Logging { @SpyBean lateinit var progressManager: ProgressManager + @Autowired + @MockBean + @Suppress("unused") // -- Used to avoid notification from being dispatched + lateinit var notificationActivityEventListener: ActivityEventListener + lateinit var util: BatchJobTestUtil @BeforeEach diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt index 4f85e24846..16142f28ea 100644 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt @@ -17,8 +17,8 @@ package io.tolgee.notifications import io.tolgee.development.testDataBuilder.data.NotificationsTestData +import io.tolgee.dtos.request.LanguageDto import io.tolgee.dtos.request.key.CreateKeyDto -import io.tolgee.dtos.request.translation.SetTranslationsWithKeyDto import io.tolgee.dtos.request.translation.comment.TranslationCommentWithLangKeyDto import io.tolgee.fixtures.andIsCreated import io.tolgee.fixtures.andIsOk @@ -55,11 +55,12 @@ class UserNotificationDebounceTest : AbstractNotificationTest() { waitUntilUserNotificationDispatch() userNotificationRepository.findAllByRecipient(testData.alice).assert.hasSize(1) - performAuthPut( - url = "/v2/projects/${testData.calmProject.id}/translations", - content = SetTranslationsWithKeyDto( - key = testData.keyCalmProject.name, - translations = mapOf("fr" to "Superb French translation!") + performAuthPost( + url = "/v2/projects/${testData.calmProject.id}/languages", + content = LanguageDto( + name = "Meow", + originalName = "meow", + tag = "meow-en", ) ).andIsOk diff --git a/backend/data/src/main/kotlin/io/tolgee/model/DismissedAnnouncement.kt b/backend/data/src/main/kotlin/io/tolgee/model/DismissedAnnouncement.kt index 482bc360dc..f52482a363 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/DismissedAnnouncement.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/DismissedAnnouncement.kt @@ -1,17 +1,26 @@ package io.tolgee.model import io.tolgee.model.enums.Announcement +import org.springframework.data.annotation.AccessType import java.io.Serializable -import javax.persistence.* +import javax.persistence.Entity +import javax.persistence.EnumType +import javax.persistence.Enumerated +import javax.persistence.FetchType +import javax.persistence.Id +import javax.persistence.IdClass +import javax.persistence.ManyToOne @Entity @IdClass(DismissedAnnouncementId::class) class DismissedAnnouncement( @Id + @AccessType(AccessType.Type.PROPERTY) @ManyToOne(fetch = FetchType.LAZY) var user: UserAccount, @Id + @AccessType(AccessType.Type.PROPERTY) @Enumerated(EnumType.STRING) var announcement: Announcement ) : Serializable diff --git a/backend/data/src/main/kotlin/io/tolgee/model/EmailVerification.kt b/backend/data/src/main/kotlin/io/tolgee/model/EmailVerification.kt index 8a1ae27a1a..04b9a9551f 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/EmailVerification.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/EmailVerification.kt @@ -1,5 +1,6 @@ package io.tolgee.model +import org.springframework.data.annotation.AccessType import javax.persistence.Entity import javax.persistence.GeneratedValue import javax.persistence.GenerationType @@ -13,6 +14,7 @@ import javax.validation.constraints.NotBlank @Table(uniqueConstraints = []) data class EmailVerification( @Id + @AccessType(AccessType.Type.PROPERTY) @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long? = null, diff --git a/backend/data/src/main/kotlin/io/tolgee/model/ForcedServerDateTime.kt b/backend/data/src/main/kotlin/io/tolgee/model/ForcedServerDateTime.kt index 7d16b44001..7d15829fb0 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/ForcedServerDateTime.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/ForcedServerDateTime.kt @@ -1,5 +1,6 @@ package io.tolgee.model +import org.springframework.data.annotation.AccessType import java.util.* import javax.persistence.Entity import javax.persistence.Id @@ -8,6 +9,7 @@ import javax.persistence.Temporal @Entity class ForcedServerDateTime { @Id + @AccessType(AccessType.Type.PROPERTY) val id = 1 @Temporal(javax.persistence.TemporalType.TIMESTAMP) diff --git a/backend/data/src/main/kotlin/io/tolgee/model/Invitation.kt b/backend/data/src/main/kotlin/io/tolgee/model/Invitation.kt index d6cdfa59e0..5512e3e367 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/Invitation.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/Invitation.kt @@ -1,5 +1,6 @@ package io.tolgee.model +import org.springframework.data.annotation.AccessType import javax.persistence.CascadeType import javax.persistence.Entity import javax.persistence.GeneratedValue @@ -18,6 +19,7 @@ import javax.validation.constraints.NotBlank ) class Invitation( @Id + @AccessType(AccessType.Type.PROPERTY) @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long? = null, var code: @NotBlank String diff --git a/backend/data/src/main/kotlin/io/tolgee/model/Organization.kt b/backend/data/src/main/kotlin/io/tolgee/model/Organization.kt index b427f0197c..a75411b361 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/Organization.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/Organization.kt @@ -1,6 +1,7 @@ package io.tolgee.model import com.fasterxml.jackson.annotation.JsonIgnore +import org.springframework.data.annotation.AccessType import javax.persistence.CascadeType import javax.persistence.Column import javax.persistence.Entity @@ -23,7 +24,9 @@ import javax.validation.constraints.Size ] ) class Organization( - @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + @Id + @AccessType(AccessType.Type.PROPERTY) + @GeneratedValue(strategy = GenerationType.IDENTITY) override var id: Long = 0, @field:NotBlank @field:Size(min = 3, max = 50) diff --git a/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt b/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt index 7e0aa3cacd..2dea105f5b 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt @@ -8,6 +8,7 @@ import io.tolgee.model.enums.Scope import org.hibernate.annotations.Parameter import org.hibernate.annotations.Type import org.hibernate.annotations.TypeDef +import org.springframework.data.annotation.AccessType import javax.persistence.Column import javax.persistence.Entity import javax.persistence.EntityListeners @@ -40,6 +41,7 @@ import javax.persistence.PreUpdate @EntityListeners(Permission.Companion.PermissionListeners::class) class Permission( @Id + @AccessType(AccessType.Type.PROPERTY) @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = 0L, diff --git a/backend/data/src/main/kotlin/io/tolgee/model/Project.kt b/backend/data/src/main/kotlin/io/tolgee/model/Project.kt index d4b6233038..9cf9dc8ab0 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/Project.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/Project.kt @@ -9,6 +9,7 @@ import io.tolgee.model.key.Key import io.tolgee.model.key.Namespace import io.tolgee.model.mtServiceConfig.MtServiceConfig import io.tolgee.model.webhook.WebhookConfig +import org.springframework.data.annotation.AccessType import java.util.* import javax.persistence.CascadeType import javax.persistence.Column @@ -35,6 +36,7 @@ import javax.validation.constraints.Size @EntityListeners(Project.Companion.ProjectListener::class) class Project( @Id + @AccessType(AccessType.Type.PROPERTY) @GeneratedValue(strategy = GenerationType.IDENTITY) override var id: Long = 0L, diff --git a/backend/data/src/main/kotlin/io/tolgee/model/StandardAuditModel.kt b/backend/data/src/main/kotlin/io/tolgee/model/StandardAuditModel.kt index f77c497ae8..cb71a6ce6a 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/StandardAuditModel.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/StandardAuditModel.kt @@ -1,5 +1,6 @@ package io.tolgee.model +import org.springframework.data.annotation.AccessType import org.springframework.data.util.ProxyUtils import javax.persistence.GeneratedValue import javax.persistence.GenerationType @@ -10,6 +11,7 @@ import javax.persistence.SequenceGenerator @MappedSuperclass abstract class StandardAuditModel : AuditModel(), EntityWithId { @Id + @AccessType(AccessType.Type.PROPERTY) @SequenceGenerator( name = "sequenceGenerator", sequenceName = "hibernate_sequence", diff --git a/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt b/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt index 40be16d379..67b0d6b541 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt @@ -7,6 +7,7 @@ import org.hibernate.annotations.ColumnDefault import org.hibernate.annotations.Type import org.hibernate.annotations.TypeDef import org.hibernate.annotations.Where +import org.springframework.data.annotation.AccessType import java.util.* import javax.persistence.CascadeType import javax.persistence.Column @@ -26,6 +27,7 @@ import javax.validation.constraints.NotBlank @TypeDef(name = "string-array", typeClass = ListArrayType::class) data class UserAccount( @Id + @AccessType(AccessType.Type.PROPERTY) @GeneratedValue(strategy = GenerationType.IDENTITY) override var id: Long = 0L, diff --git a/backend/data/src/main/kotlin/io/tolgee/model/UserPreferences.kt b/backend/data/src/main/kotlin/io/tolgee/model/UserPreferences.kt index 07b8471199..336f3f5d47 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/UserPreferences.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/UserPreferences.kt @@ -1,5 +1,6 @@ package io.tolgee.model +import org.springframework.data.annotation.AccessType import javax.persistence.Column import javax.persistence.Entity import javax.persistence.Id @@ -26,6 +27,7 @@ class UserPreferences( var preferredOrganization: Organization? = null @Id + @AccessType(AccessType.Type.PROPERTY) @Column(name = "user_account_id") var id: Long = 0 } diff --git a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityDescribingEntity.kt b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityDescribingEntity.kt index 166af57d49..e18d8f0c98 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityDescribingEntity.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityDescribingEntity.kt @@ -8,6 +8,7 @@ import org.hibernate.annotations.NotFoundAction import org.hibernate.annotations.Type import org.hibernate.annotations.TypeDef import org.hibernate.annotations.TypeDefs +import org.springframework.data.annotation.AccessType import java.io.Serializable import javax.persistence.Entity import javax.persistence.Enumerated @@ -23,13 +24,16 @@ import javax.persistence.ManyToOne class ActivityDescribingEntity( @ManyToOne @Id + @AccessType(AccessType.Type.PROPERTY) @NotFound(action = NotFoundAction.IGNORE) val activityRevision: ActivityRevision, @Id + @AccessType(AccessType.Type.PROPERTY) val entityClass: String, @Id + @AccessType(AccessType.Type.PROPERTY) val entityId: Long ) : Serializable { diff --git a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityRevision.kt b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityRevision.kt index 06b94dfb77..1fcf38c023 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityRevision.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityRevision.kt @@ -13,6 +13,7 @@ import org.hibernate.annotations.TypeDefs import org.springframework.beans.factory.ObjectFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Configurable +import org.springframework.data.annotation.AccessType import java.util.* import javax.persistence.Column import javax.persistence.Entity @@ -46,6 +47,7 @@ import javax.persistence.TemporalType ) class ActivityRevision : java.io.Serializable { @Id + @AccessType(AccessType.Type.PROPERTY) @SequenceGenerator( name = "activitySequenceGenerator", sequenceName = "activity_sequence", diff --git a/backend/data/src/main/kotlin/io/tolgee/model/contentDelivery/AzureContentStorageConfig.kt b/backend/data/src/main/kotlin/io/tolgee/model/contentDelivery/AzureContentStorageConfig.kt index 924c3d03e4..7b02663819 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/contentDelivery/AzureContentStorageConfig.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/contentDelivery/AzureContentStorageConfig.kt @@ -1,5 +1,6 @@ package io.tolgee.model.contentDelivery +import org.springframework.data.annotation.AccessType import javax.persistence.Column import javax.persistence.Entity import javax.persistence.FetchType @@ -17,6 +18,7 @@ class AzureContentStorageConfig( var contentStorage: ContentStorage, ) : AzureBlobConfig { @Id + @AccessType(AccessType.Type.PROPERTY) @Column(name = "content_storage_id") private val id: Long? = null diff --git a/backend/data/src/main/kotlin/io/tolgee/model/contentDelivery/S3ContentStorageConfig.kt b/backend/data/src/main/kotlin/io/tolgee/model/contentDelivery/S3ContentStorageConfig.kt index 2f121cfb24..83ce9edb2a 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/contentDelivery/S3ContentStorageConfig.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/contentDelivery/S3ContentStorageConfig.kt @@ -1,5 +1,6 @@ package io.tolgee.model.contentDelivery +import org.springframework.data.annotation.AccessType import javax.persistence.Column import javax.persistence.Entity import javax.persistence.FetchType @@ -9,7 +10,7 @@ import javax.persistence.MapsId import javax.persistence.OneToOne import javax.validation.constraints.NotBlank -@Entity() +@Entity class S3ContentStorageConfig( @MapsId @JoinColumn(name = "content_storage_id") @@ -17,6 +18,7 @@ class S3ContentStorageConfig( var contentStorage: ContentStorage, ) : S3Config { @Id + @AccessType(AccessType.Type.PROPERTY) @Column(name = "content_storage_id") private val id: Long? = null diff --git a/backend/data/src/main/kotlin/io/tolgee/model/notifications/NotificationPreferences.kt b/backend/data/src/main/kotlin/io/tolgee/model/notifications/NotificationPreferences.kt index 87054b17fa..6da765f939 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/notifications/NotificationPreferences.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/notifications/NotificationPreferences.kt @@ -23,6 +23,7 @@ import io.tolgee.notifications.NotificationType import org.hibernate.annotations.Parameter import org.hibernate.annotations.Type import org.hibernate.annotations.TypeDef +import org.springframework.data.annotation.AccessType import javax.persistence.Column import javax.persistence.Entity import javax.persistence.FetchType @@ -76,6 +77,7 @@ class NotificationPreferences( var disabledNotifications: Array, ) { @Id + @AccessType(AccessType.Type.PROPERTY) @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long = 0L } diff --git a/backend/data/src/main/kotlin/io/tolgee/model/notifications/UserNotification.kt b/backend/data/src/main/kotlin/io/tolgee/model/notifications/UserNotification.kt index f5614b148f..5f8c2832c2 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/notifications/UserNotification.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/notifications/UserNotification.kt @@ -23,6 +23,7 @@ import io.tolgee.model.batch.BatchJob import io.tolgee.notifications.NotificationType import org.hibernate.annotations.ColumnDefault import org.hibernate.annotations.UpdateTimestamp +import org.springframework.data.annotation.AccessType import java.util.* import javax.persistence.Column import javax.persistence.Entity @@ -67,6 +68,7 @@ class UserNotification( val batchJob: BatchJob? = null ) { @Id + @AccessType(AccessType.Type.PROPERTY) @SequenceGenerator(name = "notification_seq", sequenceName = "sequence_notifications") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "notification_seq") val id: Long = 0 diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt index f702973c4e..2583b1c05f 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt @@ -39,11 +39,9 @@ interface UserNotificationRepository : JpaRepository { @Query( """ FROM UserNotification un - INNER JOIN un.modifiedEntities me - INNER JOIN ActivityDescribingEntity de ON de.activityRevision = me.activityRevision WHERE - un.type = :type AND un.unread = true AND + un.type = :type AND un.project = :project AND un.recipient IN :recipients """ From 16de53bf8686f8309e3836b32272b50f02e834f5 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Mon, 4 Dec 2023 12:55:18 +0100 Subject: [PATCH 17/44] tests: remove unused mockbean --- .../kotlin/io/tolgee/batch/AbstractBatchJobsGeneralTest.kt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/backend/app/src/test/kotlin/io/tolgee/batch/AbstractBatchJobsGeneralTest.kt b/backend/app/src/test/kotlin/io/tolgee/batch/AbstractBatchJobsGeneralTest.kt index 3d03370a2b..4f306a9ae1 100644 --- a/backend/app/src/test/kotlin/io/tolgee/batch/AbstractBatchJobsGeneralTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/batch/AbstractBatchJobsGeneralTest.kt @@ -7,7 +7,6 @@ import io.tolgee.batch.processors.PreTranslationByTmChunkProcessor import io.tolgee.constants.Message import io.tolgee.development.testDataBuilder.data.BatchJobsTestData import io.tolgee.model.batch.BatchJobStatus -import io.tolgee.notifications.listeners.ActivityEventListener import io.tolgee.testing.WebsocketTest import io.tolgee.testing.assert import io.tolgee.util.Logging @@ -16,7 +15,6 @@ import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.mockito.Mockito import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.mock.mockito.MockBean import org.springframework.boot.test.mock.mockito.SpyBean import java.time.Duration import java.util.* @@ -63,11 +61,6 @@ abstract class AbstractBatchJobsGeneralTest : AbstractSpringTest(), Logging { @SpyBean lateinit var progressManager: ProgressManager - @Autowired - @MockBean - @Suppress("unused") // -- Used to avoid notification from being dispatched - lateinit var notificationActivityEventListener: ActivityEventListener - lateinit var util: BatchJobTestUtil @BeforeEach From 19d7c6e6de2c3d8d320fa0e0dc86c89f72b007b8 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Mon, 4 Dec 2023 15:31:23 +0100 Subject: [PATCH 18/44] fix: hibernate lazy initialization problems The amount of time spent solving made up problems instead of working on real problems... --- .../kotlin/io/tolgee/model/DismissedAnnouncement.kt | 3 --- .../main/kotlin/io/tolgee/model/EmailVerification.kt | 3 --- .../kotlin/io/tolgee/model/ForcedServerDateTime.kt | 2 -- .../data/src/main/kotlin/io/tolgee/model/Invitation.kt | 2 -- .../src/main/kotlin/io/tolgee/model/Organization.kt | 2 -- .../data/src/main/kotlin/io/tolgee/model/Permission.kt | 2 -- .../data/src/main/kotlin/io/tolgee/model/Project.kt | 10 ++++------ .../main/kotlin/io/tolgee/model/StandardAuditModel.kt | 2 -- .../src/main/kotlin/io/tolgee/model/UserAccount.kt | 2 -- .../src/main/kotlin/io/tolgee/model/UserPreferences.kt | 2 -- .../tolgee/model/activity/ActivityDescribingEntity.kt | 4 ---- .../io/tolgee/model/activity/ActivityRevision.kt | 2 -- .../model/contentDelivery/AzureContentStorageConfig.kt | 2 -- .../model/contentDelivery/S3ContentStorageConfig.kt | 2 -- .../model/notifications/NotificationPreferences.kt | 2 -- .../io/tolgee/model/notifications/UserNotification.kt | 2 -- .../notifications/listeners/ActivityEventListener.kt | 7 ++++++- .../kotlin/io/tolgee/repository/LanguageRepository.kt | 8 ++++++-- .../main/kotlin/io/tolgee/service/LanguageService.kt | 6 ++++++ 19 files changed, 22 insertions(+), 43 deletions(-) diff --git a/backend/data/src/main/kotlin/io/tolgee/model/DismissedAnnouncement.kt b/backend/data/src/main/kotlin/io/tolgee/model/DismissedAnnouncement.kt index f52482a363..80865913ee 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/DismissedAnnouncement.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/DismissedAnnouncement.kt @@ -1,7 +1,6 @@ package io.tolgee.model import io.tolgee.model.enums.Announcement -import org.springframework.data.annotation.AccessType import java.io.Serializable import javax.persistence.Entity import javax.persistence.EnumType @@ -15,12 +14,10 @@ import javax.persistence.ManyToOne @IdClass(DismissedAnnouncementId::class) class DismissedAnnouncement( @Id - @AccessType(AccessType.Type.PROPERTY) @ManyToOne(fetch = FetchType.LAZY) var user: UserAccount, @Id - @AccessType(AccessType.Type.PROPERTY) @Enumerated(EnumType.STRING) var announcement: Announcement ) : Serializable diff --git a/backend/data/src/main/kotlin/io/tolgee/model/EmailVerification.kt b/backend/data/src/main/kotlin/io/tolgee/model/EmailVerification.kt index 04b9a9551f..48da7d3b67 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/EmailVerification.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/EmailVerification.kt @@ -1,6 +1,5 @@ package io.tolgee.model -import org.springframework.data.annotation.AccessType import javax.persistence.Entity import javax.persistence.GeneratedValue import javax.persistence.GenerationType @@ -14,7 +13,6 @@ import javax.validation.constraints.NotBlank @Table(uniqueConstraints = []) data class EmailVerification( @Id - @AccessType(AccessType.Type.PROPERTY) @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long? = null, @@ -24,7 +22,6 @@ data class EmailVerification( @Email var newEmail: String? = null ) : AuditModel() { - @Suppress("JoinDeclarationAndAssignment") @OneToOne(optional = false) lateinit var userAccount: UserAccount diff --git a/backend/data/src/main/kotlin/io/tolgee/model/ForcedServerDateTime.kt b/backend/data/src/main/kotlin/io/tolgee/model/ForcedServerDateTime.kt index 7d15829fb0..7d16b44001 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/ForcedServerDateTime.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/ForcedServerDateTime.kt @@ -1,6 +1,5 @@ package io.tolgee.model -import org.springframework.data.annotation.AccessType import java.util.* import javax.persistence.Entity import javax.persistence.Id @@ -9,7 +8,6 @@ import javax.persistence.Temporal @Entity class ForcedServerDateTime { @Id - @AccessType(AccessType.Type.PROPERTY) val id = 1 @Temporal(javax.persistence.TemporalType.TIMESTAMP) diff --git a/backend/data/src/main/kotlin/io/tolgee/model/Invitation.kt b/backend/data/src/main/kotlin/io/tolgee/model/Invitation.kt index 5512e3e367..d6cdfa59e0 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/Invitation.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/Invitation.kt @@ -1,6 +1,5 @@ package io.tolgee.model -import org.springframework.data.annotation.AccessType import javax.persistence.CascadeType import javax.persistence.Entity import javax.persistence.GeneratedValue @@ -19,7 +18,6 @@ import javax.validation.constraints.NotBlank ) class Invitation( @Id - @AccessType(AccessType.Type.PROPERTY) @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long? = null, var code: @NotBlank String diff --git a/backend/data/src/main/kotlin/io/tolgee/model/Organization.kt b/backend/data/src/main/kotlin/io/tolgee/model/Organization.kt index a75411b361..e10e678b41 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/Organization.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/Organization.kt @@ -1,7 +1,6 @@ package io.tolgee.model import com.fasterxml.jackson.annotation.JsonIgnore -import org.springframework.data.annotation.AccessType import javax.persistence.CascadeType import javax.persistence.Column import javax.persistence.Entity @@ -25,7 +24,6 @@ import javax.validation.constraints.Size ) class Organization( @Id - @AccessType(AccessType.Type.PROPERTY) @GeneratedValue(strategy = GenerationType.IDENTITY) override var id: Long = 0, diff --git a/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt b/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt index 2dea105f5b..7e0aa3cacd 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt @@ -8,7 +8,6 @@ import io.tolgee.model.enums.Scope import org.hibernate.annotations.Parameter import org.hibernate.annotations.Type import org.hibernate.annotations.TypeDef -import org.springframework.data.annotation.AccessType import javax.persistence.Column import javax.persistence.Entity import javax.persistence.EntityListeners @@ -41,7 +40,6 @@ import javax.persistence.PreUpdate @EntityListeners(Permission.Companion.PermissionListeners::class) class Permission( @Id - @AccessType(AccessType.Type.PROPERTY) @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = 0L, diff --git a/backend/data/src/main/kotlin/io/tolgee/model/Project.kt b/backend/data/src/main/kotlin/io/tolgee/model/Project.kt index 9cf9dc8ab0..8ab3643859 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/Project.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/Project.kt @@ -9,7 +9,6 @@ import io.tolgee.model.key.Key import io.tolgee.model.key.Namespace import io.tolgee.model.mtServiceConfig.MtServiceConfig import io.tolgee.model.webhook.WebhookConfig -import org.springframework.data.annotation.AccessType import java.util.* import javax.persistence.CascadeType import javax.persistence.Column @@ -36,7 +35,6 @@ import javax.validation.constraints.Size @EntityListeners(Project.Companion.ProjectListener::class) class Project( @Id - @AccessType(AccessType.Type.PROPERTY) @GeneratedValue(strategy = GenerationType.IDENTITY) override var id: Long = 0L, @@ -95,16 +93,16 @@ class Project( @Transient override var disableActivityLogging = false - @OneToMany(orphanRemoval = true, mappedBy = "project") + @OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, mappedBy = "project") var automations: MutableList = mutableListOf() - @OneToMany(orphanRemoval = true, mappedBy = "project") + @OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, mappedBy = "project") var contentDeliveryConfigs: MutableList = mutableListOf() - @OneToMany(orphanRemoval = true, mappedBy = "project") + @OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, mappedBy = "project") var contentStorages: MutableList = mutableListOf() - @OneToMany(orphanRemoval = true, mappedBy = "project") + @OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, mappedBy = "project") var webhookConfigs: MutableList = mutableListOf() constructor(name: String, description: String? = null, slug: String?, organizationOwner: Organization) : diff --git a/backend/data/src/main/kotlin/io/tolgee/model/StandardAuditModel.kt b/backend/data/src/main/kotlin/io/tolgee/model/StandardAuditModel.kt index cb71a6ce6a..f77c497ae8 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/StandardAuditModel.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/StandardAuditModel.kt @@ -1,6 +1,5 @@ package io.tolgee.model -import org.springframework.data.annotation.AccessType import org.springframework.data.util.ProxyUtils import javax.persistence.GeneratedValue import javax.persistence.GenerationType @@ -11,7 +10,6 @@ import javax.persistence.SequenceGenerator @MappedSuperclass abstract class StandardAuditModel : AuditModel(), EntityWithId { @Id - @AccessType(AccessType.Type.PROPERTY) @SequenceGenerator( name = "sequenceGenerator", sequenceName = "hibernate_sequence", diff --git a/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt b/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt index 67b0d6b541..40be16d379 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt @@ -7,7 +7,6 @@ import org.hibernate.annotations.ColumnDefault import org.hibernate.annotations.Type import org.hibernate.annotations.TypeDef import org.hibernate.annotations.Where -import org.springframework.data.annotation.AccessType import java.util.* import javax.persistence.CascadeType import javax.persistence.Column @@ -27,7 +26,6 @@ import javax.validation.constraints.NotBlank @TypeDef(name = "string-array", typeClass = ListArrayType::class) data class UserAccount( @Id - @AccessType(AccessType.Type.PROPERTY) @GeneratedValue(strategy = GenerationType.IDENTITY) override var id: Long = 0L, diff --git a/backend/data/src/main/kotlin/io/tolgee/model/UserPreferences.kt b/backend/data/src/main/kotlin/io/tolgee/model/UserPreferences.kt index 336f3f5d47..07b8471199 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/UserPreferences.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/UserPreferences.kt @@ -1,6 +1,5 @@ package io.tolgee.model -import org.springframework.data.annotation.AccessType import javax.persistence.Column import javax.persistence.Entity import javax.persistence.Id @@ -27,7 +26,6 @@ class UserPreferences( var preferredOrganization: Organization? = null @Id - @AccessType(AccessType.Type.PROPERTY) @Column(name = "user_account_id") var id: Long = 0 } diff --git a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityDescribingEntity.kt b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityDescribingEntity.kt index e18d8f0c98..166af57d49 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityDescribingEntity.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityDescribingEntity.kt @@ -8,7 +8,6 @@ import org.hibernate.annotations.NotFoundAction import org.hibernate.annotations.Type import org.hibernate.annotations.TypeDef import org.hibernate.annotations.TypeDefs -import org.springframework.data.annotation.AccessType import java.io.Serializable import javax.persistence.Entity import javax.persistence.Enumerated @@ -24,16 +23,13 @@ import javax.persistence.ManyToOne class ActivityDescribingEntity( @ManyToOne @Id - @AccessType(AccessType.Type.PROPERTY) @NotFound(action = NotFoundAction.IGNORE) val activityRevision: ActivityRevision, @Id - @AccessType(AccessType.Type.PROPERTY) val entityClass: String, @Id - @AccessType(AccessType.Type.PROPERTY) val entityId: Long ) : Serializable { diff --git a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityRevision.kt b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityRevision.kt index 1fcf38c023..06b94dfb77 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityRevision.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityRevision.kt @@ -13,7 +13,6 @@ import org.hibernate.annotations.TypeDefs import org.springframework.beans.factory.ObjectFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Configurable -import org.springframework.data.annotation.AccessType import java.util.* import javax.persistence.Column import javax.persistence.Entity @@ -47,7 +46,6 @@ import javax.persistence.TemporalType ) class ActivityRevision : java.io.Serializable { @Id - @AccessType(AccessType.Type.PROPERTY) @SequenceGenerator( name = "activitySequenceGenerator", sequenceName = "activity_sequence", diff --git a/backend/data/src/main/kotlin/io/tolgee/model/contentDelivery/AzureContentStorageConfig.kt b/backend/data/src/main/kotlin/io/tolgee/model/contentDelivery/AzureContentStorageConfig.kt index 7b02663819..924c3d03e4 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/contentDelivery/AzureContentStorageConfig.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/contentDelivery/AzureContentStorageConfig.kt @@ -1,6 +1,5 @@ package io.tolgee.model.contentDelivery -import org.springframework.data.annotation.AccessType import javax.persistence.Column import javax.persistence.Entity import javax.persistence.FetchType @@ -18,7 +17,6 @@ class AzureContentStorageConfig( var contentStorage: ContentStorage, ) : AzureBlobConfig { @Id - @AccessType(AccessType.Type.PROPERTY) @Column(name = "content_storage_id") private val id: Long? = null diff --git a/backend/data/src/main/kotlin/io/tolgee/model/contentDelivery/S3ContentStorageConfig.kt b/backend/data/src/main/kotlin/io/tolgee/model/contentDelivery/S3ContentStorageConfig.kt index 83ce9edb2a..0852804ed8 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/contentDelivery/S3ContentStorageConfig.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/contentDelivery/S3ContentStorageConfig.kt @@ -1,6 +1,5 @@ package io.tolgee.model.contentDelivery -import org.springframework.data.annotation.AccessType import javax.persistence.Column import javax.persistence.Entity import javax.persistence.FetchType @@ -18,7 +17,6 @@ class S3ContentStorageConfig( var contentStorage: ContentStorage, ) : S3Config { @Id - @AccessType(AccessType.Type.PROPERTY) @Column(name = "content_storage_id") private val id: Long? = null diff --git a/backend/data/src/main/kotlin/io/tolgee/model/notifications/NotificationPreferences.kt b/backend/data/src/main/kotlin/io/tolgee/model/notifications/NotificationPreferences.kt index 6da765f939..87054b17fa 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/notifications/NotificationPreferences.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/notifications/NotificationPreferences.kt @@ -23,7 +23,6 @@ import io.tolgee.notifications.NotificationType import org.hibernate.annotations.Parameter import org.hibernate.annotations.Type import org.hibernate.annotations.TypeDef -import org.springframework.data.annotation.AccessType import javax.persistence.Column import javax.persistence.Entity import javax.persistence.FetchType @@ -77,7 +76,6 @@ class NotificationPreferences( var disabledNotifications: Array, ) { @Id - @AccessType(AccessType.Type.PROPERTY) @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long = 0L } diff --git a/backend/data/src/main/kotlin/io/tolgee/model/notifications/UserNotification.kt b/backend/data/src/main/kotlin/io/tolgee/model/notifications/UserNotification.kt index 5f8c2832c2..f5614b148f 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/notifications/UserNotification.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/notifications/UserNotification.kt @@ -23,7 +23,6 @@ import io.tolgee.model.batch.BatchJob import io.tolgee.notifications.NotificationType import org.hibernate.annotations.ColumnDefault import org.hibernate.annotations.UpdateTimestamp -import org.springframework.data.annotation.AccessType import java.util.* import javax.persistence.Column import javax.persistence.Entity @@ -68,7 +67,6 @@ class UserNotification( val batchJob: BatchJob? = null ) { @Id - @AccessType(AccessType.Type.PROPERTY) @SequenceGenerator(name = "notification_seq", sequenceName = "sequence_notifications") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "notification_seq") val id: Long = 0 diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt index 5d7f17bf3a..a78fc1f5f5 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt @@ -30,11 +30,13 @@ import io.tolgee.model.translation.Translation import io.tolgee.notifications.NotificationType import io.tolgee.notifications.dto.NotificationCreateDto import io.tolgee.notifications.events.NotificationCreateEvent +import io.tolgee.service.LanguageService import io.tolgee.util.Logging import io.tolgee.util.logger import org.springframework.context.ApplicationEventPublisher import org.springframework.context.event.EventListener import org.springframework.stereotype.Component +import org.springframework.transaction.annotation.Transactional import javax.persistence.EntityManager private typealias SortedTranslations = List>> @@ -43,8 +45,10 @@ private typealias SortedTranslations = List = e.activityRevision.modifiedEntities ) { + val baseLanguageId = languageService.getBaseLanguageForProject(project) val sortedTranslations = sortTranslations( modifiedEntities, - baseLanguage = project.baseLanguage?.id ?: 0L + baseLanguage = baseLanguageId ?: 0L ) for ((type, translations) in sortedTranslations) { diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt index 8a0f7aa6fb..08f0ba2aa7 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt @@ -1,6 +1,7 @@ package io.tolgee.repository import io.tolgee.model.Language +import io.tolgee.model.Project import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable import org.springframework.data.jpa.repository.JpaRepository @@ -10,8 +11,8 @@ import java.util.* @Repository interface LanguageRepository : JpaRepository { - fun findByTagAndProject(abbreviation: String, project: io.tolgee.model.Project): Optional - fun findByNameAndProject(name: String?, project: io.tolgee.model.Project): Optional + fun findByTagAndProject(abbreviation: String, project: Project): Optional + fun findByNameAndProject(name: String?, project: Project): Optional fun findByTagAndProjectId(abbreviation: String?, projectId: Long): Optional fun findAllByProjectId(projectId: Long?): Set fun findAllByProjectId(projectId: Long?, pageable: Pageable): Page @@ -28,4 +29,7 @@ interface LanguageRepository : JpaRepository { """ ) fun findLanguageIdsOfTranslations(translationIds: List): List> + + @Query("SELECT l.id FROM Language l, Project p WHERE p = :project AND l = p.baseLanguage") + fun getBaseLanguageForProject(project: Project): Long? } diff --git a/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt b/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt index 10234567bc..1ae2726087 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt @@ -12,6 +12,7 @@ import io.tolgee.service.project.ProjectService import io.tolgee.service.security.PermissionService import io.tolgee.service.security.SecurityService import io.tolgee.service.translation.TranslationService +import org.hibernate.Hibernate import org.springframework.beans.factory.annotation.Autowired import org.springframework.context.annotation.Lazy import org.springframework.data.domain.Page @@ -193,4 +194,9 @@ class LanguageService( fun getLanguageIdsByTags(projectId: Long, languageTags: Collection): Map { return languageRepository.findAllByTagInAndProjectId(languageTags, projectId).associateBy { it.tag } } + + fun getBaseLanguageForProject(project: Project): Long? { + if (Hibernate.isInitialized(project)) return project.baseLanguage?.id + return languageRepository.getBaseLanguageForProject(project) + } } From e612c0c83b649f6e3c0338edb94b50115cb3ea20 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Wed, 13 Dec 2023 15:33:21 +0100 Subject: [PATCH 19/44] feat: implement notification http endpoints --- .../v2/controllers/InitialDataController.kt | 3 + .../NotificationPreferencesController.kt | 120 ++++++++++++++ .../notifications/NotificationsController.kt | 113 +++++++++++++ .../io/tolgee/hateoas/InitialDataModel.kt | 6 +- .../notifications/UserNotificationModel.kt | 37 +++++ .../UserNotificationModelAssembler.kt | 68 ++++++++ .../websocket/ActivityWebsocketListener.kt | 2 +- .../io/tolgee/activity/ActivityService.kt | 4 +- .../ActivityViewByRevisionsProvider.kt | 108 ++----------- .../views/ModifiedEntitiesViewProvider.kt | 153 ++++++++++++++++++ .../ProjectActivityViewByPageableProvider.kt | 4 +- .../ProjectActivityViewByRevisionProvider.kt | 2 +- .../RelationDescriptionExtractor.kt | 2 +- .../model/notifications/UserNotification.kt | 2 +- .../activity/SimpleModifiedEntityView.kt | 29 ++++ .../NotificationPreferencesService.kt | 90 +++++++++++ .../notifications/NotificationStatus.kt | 21 +++ .../notifications/UserNotificationService.kt | 45 ++++-- .../dto/NotificationCreateDto.kt | 2 +- .../dto/NotificationPreferencesDto.kt | 38 +++++ .../events/UserNotificationPushEvent.kt | 5 +- .../NotificationPreferencesRepository.kt | 6 + .../UserNotificationRepository.kt | 54 ++++--- 23 files changed, 767 insertions(+), 147 deletions(-) create mode 100644 backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationPreferencesController.kt create mode 100644 backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationsController.kt create mode 100644 backend/api/src/main/kotlin/io/tolgee/hateoas/notifications/UserNotificationModel.kt create mode 100644 backend/api/src/main/kotlin/io/tolgee/hateoas/notifications/UserNotificationModelAssembler.kt rename backend/data/src/main/kotlin/io/tolgee/activity/{projectActivityView => views}/ActivityViewByRevisionsProvider.kt (52%) create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/views/ModifiedEntitiesViewProvider.kt rename backend/data/src/main/kotlin/io/tolgee/activity/{projectActivityView => views}/ProjectActivityViewByPageableProvider.kt (91%) rename backend/data/src/main/kotlin/io/tolgee/activity/{projectActivityView => views}/ProjectActivityViewByRevisionProvider.kt (95%) rename backend/data/src/main/kotlin/io/tolgee/activity/{projectActivityView => views}/RelationDescriptionExtractor.kt (94%) create mode 100644 backend/data/src/main/kotlin/io/tolgee/model/views/activity/SimpleModifiedEntityView.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/NotificationStatus.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationPreferencesDto.kt diff --git a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/InitialDataController.kt b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/InitialDataController.kt index ff63ea7e08..444dbfce80 100644 --- a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/InitialDataController.kt +++ b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/InitialDataController.kt @@ -6,6 +6,7 @@ import io.tolgee.component.PreferredOrganizationFacade import io.tolgee.ee.api.v2.hateoas.eeSubscription.EeSubscriptionModelAssembler import io.tolgee.ee.service.EeSubscriptionService import io.tolgee.hateoas.InitialDataModel +import io.tolgee.notifications.UserNotificationService import io.tolgee.security.authentication.AuthenticationFacade import io.tolgee.service.security.UserPreferencesService import org.springframework.web.bind.annotation.CrossOrigin @@ -30,6 +31,7 @@ class InitialDataController( private val eeSubscriptionModelAssembler: EeSubscriptionModelAssembler, private val eeSubscriptionService: EeSubscriptionService, private val announcementController: AnnouncementController, + private val userNotificationService: UserNotificationService, ) : IController { @GetMapping(value = [""]) @Operation(description = "Returns initial data always required by frontend") @@ -46,6 +48,7 @@ class InitialDataController( data.preferredOrganization = preferredOrganizationFacade.getPreferred() data.languageTag = userPreferencesService.find(userAccount.id)?.language data.announcement = announcementController.getLatest() + data.unreadNotifications = userNotificationService.getUnreadNotificationsCount(userAccount.id) } return data diff --git a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationPreferencesController.kt b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationPreferencesController.kt new file mode 100644 index 0000000000..0aa3c3ec35 --- /dev/null +++ b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationPreferencesController.kt @@ -0,0 +1,120 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.api.v2.controllers.notifications + +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag +import io.tolgee.notifications.NotificationPreferencesService +import io.tolgee.notifications.dto.NotificationPreferencesDto +import io.tolgee.security.authentication.AuthenticationFacade +import org.springframework.http.HttpHeaders +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.validation.annotation.Validated +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.ResponseStatus +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping(value = ["/v2/notifications/preferences"]) +@Tag(name = "Notification preferences") +class NotificationPreferencesController( + private val authenticationFacade: AuthenticationFacade, + private val notificationPreferencesService: NotificationPreferencesService, +) { + @GetMapping("") + @Operation(summary = "Fetch the global preferences and all overrides of the current user") + fun getAllPreferences(): Map { + return notificationPreferencesService.getAllPreferences(authenticationFacade.authenticatedUser.id) + } + + @GetMapping("/global") + @Operation(summary = "Fetch the global preferences for the current user") + fun getGlobalPreferences(): NotificationPreferencesDto { + return notificationPreferencesService.getGlobalPreferences(authenticationFacade.authenticatedUser.id) + } + + @PutMapping("/global") + @Operation(summary = "Update the global notification preferences of the current user") + fun updateGlobalPreferences( + @RequestBody @Validated preferencesDto: NotificationPreferencesDto, + ): NotificationPreferencesDto { + val updated = notificationPreferencesService.setPreferencesOfUser( + authenticationFacade.authenticatedUser.id, + preferencesDto, + ) + + return NotificationPreferencesDto.fromEntity(updated) + } + + @GetMapping("/project/{id}") + @Operation(summary = "Fetch the notification preferences of the current user for a specific project") + fun getPerProjectPreferences(@PathVariable("id") id: Long): NotificationPreferencesDto { + return notificationPreferencesService.getProjectPreferences( + authenticationFacade.authenticatedUser.id, + id, + ) + } + + @PutMapping("/project/{id}") + @Operation(summary = "Update the notification preferences of the current user for a specific project") + fun updatePerProjectPreferences( + @PathVariable("id") id: Long, + @RequestBody @Validated preferencesDto: NotificationPreferencesDto, + ): NotificationPreferencesDto { + val updated = notificationPreferencesService.setProjectPreferencesOfUser( + authenticationFacade.authenticatedUser.id, + id, + preferencesDto, + ) + + return NotificationPreferencesDto.fromEntity(updated) + } + + @DeleteMapping("/project/{id}") + @ResponseStatus(HttpStatus.NO_CONTENT) + @Operation(summary = "Delete the notification preferences of the current user for a specific project") + fun deletePerProjectPreferences(@PathVariable("id") id: Long) { + notificationPreferencesService.deleteProjectPreferencesOfUser( + authenticationFacade.authenticatedUser.id, + id, + ) + } + + @PostMapping("/project/{id}/subscribe") + @Operation(summary = "Subscribe to notifications for a given project") + fun subscribeToProject(@PathVariable("id") id: Long): ResponseEntity { + return ResponseEntity( + "Coming soon! Please see https://github.com/tolgee/tolgee-platform/issues/1360 for progress on this. :D", + HttpHeaders().also { + @Suppress("UastIncorrectHttpHeaderInspection") + it.add( + "x-hey-curious-reader", + "oh hey there, didn't expect you here... " + + "if you're here, might as well join us! https://tolgee.io/career" + ) + }, + HttpStatus.NOT_IMPLEMENTED, + ) + } +} diff --git a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationsController.kt b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationsController.kt new file mode 100644 index 0000000000..e9182da6e1 --- /dev/null +++ b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationsController.kt @@ -0,0 +1,113 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.api.v2.controllers.notifications + +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag +import io.tolgee.hateoas.notifications.UserNotificationModel +import io.tolgee.hateoas.notifications.UserNotificationModelAssembler +import io.tolgee.notifications.NotificationStatus +import io.tolgee.notifications.UserNotificationService +import io.tolgee.security.authentication.AuthenticationFacade +import org.springdoc.api.annotations.ParameterObject +import org.springframework.data.domain.Pageable +import org.springframework.http.HttpStatus +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.ResponseStatus +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping(value = ["/v2/notifications"]) +@Tag(name = "Notifications") +class NotificationsController( + private val authenticationFacade: AuthenticationFacade, + private val userNotificationService: UserNotificationService, + private val userNotificationModelAssembler: UserNotificationModelAssembler, +) { + @GetMapping("/") + @Operation(summary = "Fetch the current user's notifications") + fun getNotifications( + @RequestParam("status", defaultValue = "UNREAD,READ") status: Set, + @ParameterObject pageable: Pageable, + ): List { + val notifications = userNotificationService.findNotificationsOfUserFilteredPaged( + authenticationFacade.authenticatedUser.id, + status, + pageable, + ) + + return notifications.map { userNotificationModelAssembler.toModel(it) } + } + + @PostMapping("/mark-as-read") + @ResponseStatus(HttpStatus.NO_CONTENT) + @Operation(summary = "Marks a given set of notifications as read.") + fun markNotificationsAsRead(@RequestBody notifications: List) { + userNotificationService.markAsRead( + authenticationFacade.authenticatedUser.id, + notifications, + ) + } + + @PostMapping("/mark-as-read/all") + @ResponseStatus(HttpStatus.NO_CONTENT) + @Operation(summary = "Marks all notifications as read.") + fun markAllNotificationsAsRead() { + userNotificationService.markAllAsRead(authenticationFacade.authenticatedUser.id) + } + + @PostMapping("/mark-as-unread") + @ResponseStatus(HttpStatus.NO_CONTENT) + @Operation(summary = "Marks a given set of notifications as unread.") + fun markNotificationsAsUnread(@RequestBody notifications: List) { + userNotificationService.markAsUnread( + authenticationFacade.authenticatedUser.id, + notifications, + ) + } + + @PostMapping("/mark-as-done") + @ResponseStatus(HttpStatus.NO_CONTENT) + @Operation(summary = "Marks a given set of notifications as done.") + fun markNotificationsAsDone(@RequestBody notifications: List) { + userNotificationService.markAsDone( + authenticationFacade.authenticatedUser.id, + notifications, + ) + } + + @PostMapping("/mark-as-done/all") + @ResponseStatus(HttpStatus.NO_CONTENT) + @Operation(summary = "Marks all notifications as done.") + fun markAllNotificationsAsDone() { + userNotificationService.markAllAsDone(authenticationFacade.authenticatedUser.id) + } + + @PostMapping("/unmark-as-done") + @ResponseStatus(HttpStatus.NO_CONTENT) + @Operation(summary = "Un-marks a given set of notifications as done.") + fun unmarkNotificationsAsDone(@RequestBody notifications: Collection) { + userNotificationService.unmarkAsDone( + authenticationFacade.authenticatedUser.id, + notifications, + ) + } +} diff --git a/backend/api/src/main/kotlin/io/tolgee/hateoas/InitialDataModel.kt b/backend/api/src/main/kotlin/io/tolgee/hateoas/InitialDataModel.kt index 1538cfa407..a209273ae2 100644 --- a/backend/api/src/main/kotlin/io/tolgee/hateoas/InitialDataModel.kt +++ b/backend/api/src/main/kotlin/io/tolgee/hateoas/InitialDataModel.kt @@ -6,11 +6,13 @@ import io.tolgee.ee.api.v2.hateoas.eeSubscription.EeSubscriptionModel import io.tolgee.hateoas.organization.PrivateOrganizationModel import io.tolgee.hateoas.user_account.PrivateUserAccountModel -class InitialDataModel( +@Suppress("unused") +data class InitialDataModel( val serverConfiguration: PublicConfigurationDTO, var userInfo: PrivateUserAccountModel? = null, var preferredOrganization: PrivateOrganizationModel? = null, var languageTag: String? = null, val eeSubscription: EeSubscriptionModel? = null, - var announcement: AnnouncementDto? = null + var announcement: AnnouncementDto? = null, + var unreadNotifications: Int? = null, ) diff --git a/backend/api/src/main/kotlin/io/tolgee/hateoas/notifications/UserNotificationModel.kt b/backend/api/src/main/kotlin/io/tolgee/hateoas/notifications/UserNotificationModel.kt new file mode 100644 index 0000000000..141050165e --- /dev/null +++ b/backend/api/src/main/kotlin/io/tolgee/hateoas/notifications/UserNotificationModel.kt @@ -0,0 +1,37 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.hateoas.notifications + +import io.tolgee.hateoas.batch.BatchJobModel +import io.tolgee.hateoas.project.SimpleProjectModel +import io.tolgee.model.views.activity.SimpleModifiedEntityView +import io.tolgee.notifications.NotificationType +import org.springframework.hateoas.RepresentationModel +import java.io.Serializable +import java.util.* + +@Suppress("unused") +class UserNotificationModel( + val id: Long, + val type: NotificationType, + val project: SimpleProjectModel?, + val batchJob: BatchJobModel?, + val modifiedEntities: List?, + val unread: Boolean, + val markedDoneAt: Date?, + val lastUpdated: Date, +) : RepresentationModel(), Serializable diff --git a/backend/api/src/main/kotlin/io/tolgee/hateoas/notifications/UserNotificationModelAssembler.kt b/backend/api/src/main/kotlin/io/tolgee/hateoas/notifications/UserNotificationModelAssembler.kt new file mode 100644 index 0000000000..67e8013471 --- /dev/null +++ b/backend/api/src/main/kotlin/io/tolgee/hateoas/notifications/UserNotificationModelAssembler.kt @@ -0,0 +1,68 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.hateoas.notifications + +import io.tolgee.activity.views.ModifiedEntitiesViewProvider +import io.tolgee.api.v2.controllers.notifications.NotificationsController +import io.tolgee.batch.BatchJobService +import io.tolgee.hateoas.batch.BatchJobModelAssembler +import io.tolgee.hateoas.project.SimpleProjectModelAssembler +import io.tolgee.model.activity.ActivityModifiedEntity +import io.tolgee.model.notifications.UserNotification +import io.tolgee.model.views.activity.SimpleModifiedEntityView +import org.springframework.context.ApplicationContext +import org.springframework.hateoas.server.mvc.RepresentationModelAssemblerSupport +import org.springframework.stereotype.Component + +@Component +class UserNotificationModelAssembler( + private val batchJobService: BatchJobService, + private val simpleProjectModelAssembler: SimpleProjectModelAssembler, + private val batchJobModelAssembler: BatchJobModelAssembler, + private val applicationContext: ApplicationContext, +) : RepresentationModelAssemblerSupport( + NotificationsController::class.java, UserNotificationModel::class.java +) { + override fun toModel(entity: UserNotification): UserNotificationModel { + val project = entity.project?.let { simpleProjectModelAssembler.toModel(it) } + val modifiedEntities = assembleEntityChanges(entity.modifiedEntities).ifEmpty { null } + val batchJob = entity.batchJob?.let { + val view = batchJobService.getView(it) + batchJobModelAssembler.toModel(view) + } + + return UserNotificationModel( + id = entity.id, + type = entity.type, + project = project, + batchJob = batchJob, + modifiedEntities = modifiedEntities, + unread = entity.unread, + markedDoneAt = entity.markedDoneAt, + lastUpdated = entity.lastUpdated, + ) + } + + private fun assembleEntityChanges(modifiedEntities: List): List { + val provider = ModifiedEntitiesViewProvider( + applicationContext, + modifiedEntities + ) + + return provider.getSimple() + } +} diff --git a/backend/api/src/main/kotlin/io/tolgee/websocket/ActivityWebsocketListener.kt b/backend/api/src/main/kotlin/io/tolgee/websocket/ActivityWebsocketListener.kt index 8e5bdb2b94..ae029e6a1b 100644 --- a/backend/api/src/main/kotlin/io/tolgee/websocket/ActivityWebsocketListener.kt +++ b/backend/api/src/main/kotlin/io/tolgee/websocket/ActivityWebsocketListener.kt @@ -1,6 +1,6 @@ package io.tolgee.websocket -import io.tolgee.activity.projectActivityView.RelationDescriptionExtractor +import io.tolgee.activity.views.RelationDescriptionExtractor import io.tolgee.batch.OnBatchJobCompleted import io.tolgee.batch.WebsocketProgressInfo import io.tolgee.batch.events.OnBatchJobCancelled diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/ActivityService.kt b/backend/data/src/main/kotlin/io/tolgee/activity/ActivityService.kt index 6d8bd31c2d..8ec10a37b6 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/ActivityService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/ActivityService.kt @@ -1,8 +1,8 @@ package io.tolgee.activity import io.tolgee.activity.data.ActivityType -import io.tolgee.activity.projectActivityView.ProjectActivityViewByPageableProvider -import io.tolgee.activity.projectActivityView.ProjectActivityViewByRevisionProvider +import io.tolgee.activity.views.ProjectActivityViewByPageableProvider +import io.tolgee.activity.views.ProjectActivityViewByRevisionProvider import io.tolgee.dtos.query_results.TranslationHistoryView import io.tolgee.events.OnProjectActivityStoredEvent import io.tolgee.model.activity.ActivityRevision diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/projectActivityView/ActivityViewByRevisionsProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/views/ActivityViewByRevisionsProvider.kt similarity index 52% rename from backend/data/src/main/kotlin/io/tolgee/activity/projectActivityView/ActivityViewByRevisionsProvider.kt rename to backend/data/src/main/kotlin/io/tolgee/activity/views/ActivityViewByRevisionsProvider.kt index 721d75e4df..36f23f6a1d 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/projectActivityView/ActivityViewByRevisionsProvider.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/views/ActivityViewByRevisionsProvider.kt @@ -1,12 +1,7 @@ -package io.tolgee.activity.projectActivityView +package io.tolgee.activity.views -import io.sentry.Sentry -import io.tolgee.activity.annotation.ActivityReturnsExistence import io.tolgee.activity.data.ActivityType -import io.tolgee.activity.data.EntityDescriptionRef -import io.tolgee.activity.data.ExistenceEntityDescription import io.tolgee.model.UserAccount -import io.tolgee.model.activity.ActivityDescribingEntity import io.tolgee.model.activity.ActivityModifiedEntity import io.tolgee.model.activity.ActivityModifiedEntity_ import io.tolgee.model.activity.ActivityRevision @@ -15,7 +10,6 @@ import io.tolgee.model.views.activity.ModifiedEntityView import io.tolgee.model.views.activity.ProjectActivityView import io.tolgee.repository.activity.ActivityRevisionRepository import io.tolgee.service.security.UserAccountService -import io.tolgee.util.EntityUtil import org.springframework.context.ApplicationContext import javax.persistence.EntityManager import javax.persistence.criteria.Predicate @@ -33,17 +27,12 @@ class ActivityViewByRevisionsProvider( private val entityManager: EntityManager = applicationContext.getBean(EntityManager::class.java) - private val entityUtil: EntityUtil = - applicationContext.getBean(EntityUtil::class.java) - private lateinit var authors: Map private lateinit var modifiedEntities: Map> private lateinit var revisionIds: MutableList private lateinit var counts: MutableMap> private lateinit var allDataReturningEventTypes: List - private lateinit var allRelationData: Map> private lateinit var rawModifiedEntities: List - private lateinit var entityExistences: Map, Boolean> private lateinit var params: Map fun get(): List { @@ -71,15 +60,17 @@ class ActivityViewByRevisionsProvider( private fun prepareData() { revisionIds = revisions.map { it.id }.toMutableList() - allDataReturningEventTypes = ActivityType.values().filter { !it.onlyCountsInList } - - allRelationData = getAllowedRevisionRelations(revisionIds, allDataReturningEventTypes) + allDataReturningEventTypes = ActivityType.entries.filter { !it.onlyCountsInList } rawModifiedEntities = getModifiedEntitiesRaw() - entityExistences = getEntityExistences() + val modifiedEntitiesViewProvider = ModifiedEntitiesViewProvider( + applicationContext, + rawModifiedEntities + ) - modifiedEntities = this.getModifiedEntities() + modifiedEntities = modifiedEntitiesViewProvider.get() + .groupBy { it.activityRevision.id } params = getParams() @@ -105,7 +96,7 @@ class ActivityViewByRevisionsProvider( } private fun getCounts(): MutableMap> { - val allowedTypes = ActivityType.values().filter { it.onlyCountsInList } + val allowedTypes = ActivityType.entries.filter { it.onlyCountsInList } val counts: MutableMap> = mutableMapOf() activityRevisionRepository.getModifiedEntityTypeCounts( revisionIds = revisionIds, @@ -123,66 +114,6 @@ class ActivityViewByRevisionsProvider( revisions.mapNotNull { it.authorId }.toSet() ).associateBy { it.id } - private fun getAllowedRevisionRelations( - revisionIds: List, - allowedTypes: Collection - ): Map> { - return activityRevisionRepository.getRelationsForRevisions(revisionIds, allowedTypes) - .groupBy { it.activityRevision.id } - } - - private fun getModifiedEntities(): Map> { - return rawModifiedEntities.map { modifiedEntity -> - val relations = modifiedEntity.describingRelations - ?.mapNotNull relationsOfEntityMap@{ relationEntry -> - relationEntry.key to extractCompressedRef( - relationEntry.value, - allRelationData[modifiedEntity.activityRevision.id] ?: let { - Sentry.captureException( - IllegalStateException("No relation data for revision ${modifiedEntity.activityRevision.id}") - ) - return@relationsOfEntityMap null - } - ) - }?.toMap() - ModifiedEntityView( - activityRevision = modifiedEntity.activityRevision, - entityClass = modifiedEntity.entityClass, - entityId = modifiedEntity.entityId, - exists = entityExistences[modifiedEntity.entityClass to modifiedEntity.entityId], - modifications = modifiedEntity.modifications, - description = modifiedEntity.describingData, - describingRelations = relations - ) - }.groupBy { it.activityRevision.id } - } - - private fun getEntityExistences(): Map, Boolean> { - val modifiedEntityClassIdPairs = rawModifiedEntities.map { it.entityClass to it.entityId } - val relationsClassIdPairs = allRelationData.flatMap { (_, data) -> data.map { it.entityClass to it.entityId } } - val entities = (modifiedEntityClassIdPairs + relationsClassIdPairs).toHashSet() - - return entities - .groupBy { (entityClass, _) -> entityClass } - .mapNotNull { (entityClassName, classIdPairs) -> - val entityClass = entityUtil.getRealEntityClass(entityClassName) - val annotation = entityClass?.getAnnotation(ActivityReturnsExistence::class.java) - if (annotation != null) { - val cb = entityManager.criteriaBuilder - val query = cb.createQuery(Long::class.java) - val root = query.from(entityClass) - val ids = classIdPairs.map { it.second } - query.select(root.get("id")) - query.where(root.get("id").`in`(ids)) - val existingIds = entityManager.createQuery(query).resultList - return@mapNotNull (entityClassName to ids.map { it to existingIds.contains(it) }) - } - return@mapNotNull null - } - .flatMap { (entityClassName, existingIds) -> existingIds.map { (entityClassName to it.first) to it.second } } - .toMap() - } - private fun getModifiedEntitiesRaw(): List { val cb = entityManager.criteriaBuilder val query = cb.createQuery(ActivityModifiedEntity::class.java) @@ -192,7 +123,7 @@ class ActivityViewByRevisionsProvider( val whereConditions = mutableListOf() whereConditions.add(revision.get(ActivityRevision_.type).`in`(allDataReturningEventTypes)) whereConditions.add(revision.get(ActivityRevision_.id).`in`(revisionIds)) - ActivityType.values().forEach { + ActivityType.entries.forEach { it.restrictEntitiesInList?.let { restrictEntitiesInList -> val restrictedEntityNames = restrictEntitiesInList.map { it.simpleName } whereConditions.add( @@ -207,23 +138,4 @@ class ActivityViewByRevisionsProvider( query.where(cb.and(*whereConditions.toTypedArray())) return entityManager.createQuery(query).resultList } - - private fun extractCompressedRef( - value: EntityDescriptionRef, - describingEntities: List - ): ExistenceEntityDescription { - val entity = describingEntities.find { it.entityClass == value.entityClass && it.entityId == value.entityId } - - val relations = entity?.describingRelations - ?.map { it.key to extractCompressedRef(it.value, describingEntities) } - ?.toMap() - - return ExistenceEntityDescription( - entityClass = value.entityClass, - entityId = value.entityId, - exists = entityExistences[value.entityClass to value.entityId], - data = entity?.data ?: mapOf(), - relations = relations ?: mapOf() - ) - } } diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/views/ModifiedEntitiesViewProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/views/ModifiedEntitiesViewProvider.kt new file mode 100644 index 0000000000..e4d04e92f5 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/views/ModifiedEntitiesViewProvider.kt @@ -0,0 +1,153 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.activity.views + +import io.sentry.Sentry +import io.tolgee.activity.annotation.ActivityReturnsExistence +import io.tolgee.activity.data.ActivityType +import io.tolgee.activity.data.EntityDescriptionRef +import io.tolgee.activity.data.ExistenceEntityDescription +import io.tolgee.model.activity.ActivityDescribingEntity +import io.tolgee.model.activity.ActivityModifiedEntity +import io.tolgee.model.views.activity.ModifiedEntityView +import io.tolgee.model.views.activity.SimpleModifiedEntityView +import io.tolgee.repository.activity.ActivityRevisionRepository +import io.tolgee.service.security.UserAccountService +import io.tolgee.util.EntityUtil +import org.springframework.context.ApplicationContext +import javax.persistence.EntityManager + +class ModifiedEntitiesViewProvider( + applicationContext: ApplicationContext, + private val modifiedEntities: Collection +) { + val userAccountService: UserAccountService = + applicationContext.getBean(UserAccountService::class.java) + + private val activityRevisionRepository: ActivityRevisionRepository = + applicationContext.getBean(ActivityRevisionRepository::class.java) + + private val entityManager: EntityManager = + applicationContext.getBean(EntityManager::class.java) + + private val entityUtil: EntityUtil = + applicationContext.getBean(EntityUtil::class.java) + + private val describingEntities: Map> by lazy { fetchAllowedRevisionRelations() } + + private val entityExistences: Map, Boolean> by lazy { fetchEntityExistences() } + + fun get(): List { + return modifiedEntities.map entities@{ entity -> + val relations = getRelations(entity) + ModifiedEntityView( + activityRevision = entity.activityRevision, + entityClass = entity.entityClass, + entityId = entity.entityId, + exists = entityExistences[entity.entityClass to entity.entityId], + modifications = entity.modifications, + description = entity.describingData, + describingRelations = relations + ) + } + } + + fun getSimple(): List { + return modifiedEntities.map entities@{ entity -> + val relations = getRelations(entity) + SimpleModifiedEntityView( + entityClass = entity.entityClass, + entityId = entity.entityId, + exists = entityExistences[entity.entityClass to entity.entityId], + modifications = entity.modifications, + description = entity.describingData, + describingRelations = relations + ) + } + } + + private fun getRelations(entity: ActivityModifiedEntity): Map? { + return entity.describingRelations + ?.mapNotNull { + Pair( + it.key, + extractCompressedRef( + it.value, + describingEntities[entity.activityRevision.id] ?: let { _ -> + Sentry.captureException( + IllegalStateException("No relation data for revision ${entity.activityRevision.id}") + ) + return@mapNotNull null + } + ) + ) + } + ?.toMap() + } + + private fun fetchAllowedRevisionRelations(): Map> { + val revisionIds = modifiedEntities.map { it.activityRevision.id } + val allowedTypes = ActivityType.entries.filter { !it.onlyCountsInList } + return activityRevisionRepository.getRelationsForRevisions(revisionIds, allowedTypes) + .groupBy { it.activityRevision.id } + } + + private fun fetchEntityExistences(): Map, Boolean> { + val modifiedEntityClassIdPairs = modifiedEntities.map { it.entityClass to it.entityId } + val relationsClassIdPairs = describingEntities.flatMap { (_, data) -> data.map { it.entityClass to it.entityId } } + val entities = (modifiedEntityClassIdPairs + relationsClassIdPairs).toHashSet() + + return entities + .groupBy { (entityClass, _) -> entityClass } + .mapNotNull { (entityClassName, classIdPairs) -> + val entityClass = entityUtil.getRealEntityClass(entityClassName) + val annotation = entityClass?.getAnnotation(ActivityReturnsExistence::class.java) + if (annotation != null) { + val cb = entityManager.criteriaBuilder + val query = cb.createQuery(Long::class.java) + val root = query.from(entityClass) + val ids = classIdPairs.map { it.second } + query.select(root.get("id")) + query.where(root.get("id").`in`(ids)) + val existingIds = entityManager.createQuery(query).resultList + return@mapNotNull (entityClassName to ids.map { it to existingIds.contains(it) }) + } + return@mapNotNull null + } + .flatMap { (entityClassName, existingIds) -> existingIds.map { (entityClassName to it.first) to it.second } } + .toMap() + } + + private fun extractCompressedRef( + value: EntityDescriptionRef, + describingEntities: List + ): ExistenceEntityDescription { + val entity = describingEntities.find { it.entityClass == value.entityClass && it.entityId == value.entityId } + + val relations = entity?.describingRelations + ?.map { it.key to extractCompressedRef(it.value, describingEntities) } + ?.toMap() + + return ExistenceEntityDescription( + entityClass = value.entityClass, + entityId = value.entityId, + exists = entityExistences[value.entityClass to value.entityId], + data = entity?.data ?: mapOf(), + relations = relations ?: mapOf() + ) + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/projectActivityView/ProjectActivityViewByPageableProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/views/ProjectActivityViewByPageableProvider.kt similarity index 91% rename from backend/data/src/main/kotlin/io/tolgee/activity/projectActivityView/ProjectActivityViewByPageableProvider.kt rename to backend/data/src/main/kotlin/io/tolgee/activity/views/ProjectActivityViewByPageableProvider.kt index 1b31a1d57f..5825b0e90a 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/projectActivityView/ProjectActivityViewByPageableProvider.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/views/ProjectActivityViewByPageableProvider.kt @@ -1,4 +1,4 @@ -package io.tolgee.activity.projectActivityView +package io.tolgee.activity.views import io.tolgee.activity.data.ActivityType import io.tolgee.model.activity.ActivityRevision @@ -22,7 +22,7 @@ class ProjectActivityViewByPageableProvider( } private fun getProjectActivityRevisions(projectId: Long, pageable: Pageable): Page { - val types = ActivityType.values().filter { !it.hideInList } + val types = ActivityType.entries.filter { !it.hideInList } return activityRevisionRepository.getForProject(projectId, pageable, types) } private val activityRevisionRepository: ActivityRevisionRepository = diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/projectActivityView/ProjectActivityViewByRevisionProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/views/ProjectActivityViewByRevisionProvider.kt similarity index 95% rename from backend/data/src/main/kotlin/io/tolgee/activity/projectActivityView/ProjectActivityViewByRevisionProvider.kt rename to backend/data/src/main/kotlin/io/tolgee/activity/views/ProjectActivityViewByRevisionProvider.kt index 24a58e7f30..1601ea8813 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/projectActivityView/ProjectActivityViewByRevisionProvider.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/views/ProjectActivityViewByRevisionProvider.kt @@ -1,4 +1,4 @@ -package io.tolgee.activity.projectActivityView +package io.tolgee.activity.views import io.tolgee.model.activity.ActivityRevision import io.tolgee.model.views.activity.ProjectActivityView diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/projectActivityView/RelationDescriptionExtractor.kt b/backend/data/src/main/kotlin/io/tolgee/activity/views/RelationDescriptionExtractor.kt similarity index 94% rename from backend/data/src/main/kotlin/io/tolgee/activity/projectActivityView/RelationDescriptionExtractor.kt rename to backend/data/src/main/kotlin/io/tolgee/activity/views/RelationDescriptionExtractor.kt index c75dd93cf9..a96edc349a 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/projectActivityView/RelationDescriptionExtractor.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/views/RelationDescriptionExtractor.kt @@ -1,4 +1,4 @@ -package io.tolgee.activity.projectActivityView +package io.tolgee.activity.views import io.tolgee.activity.data.EntityDescriptionRef import io.tolgee.activity.data.EntityDescriptionWithRelations diff --git a/backend/data/src/main/kotlin/io/tolgee/model/notifications/UserNotification.kt b/backend/data/src/main/kotlin/io/tolgee/model/notifications/UserNotification.kt index f5614b148f..c81ddf93d9 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/notifications/UserNotification.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/notifications/UserNotification.kt @@ -60,7 +60,7 @@ class UserNotification( // We most definitely need this to show the notification: eager @ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "user_notification_modified_entities") - val modifiedEntities: MutableSet = mutableSetOf(), + val modifiedEntities: MutableList = mutableListOf(), // We most definitely need this to show the notification: eager @ManyToOne(fetch = FetchType.EAGER) diff --git a/backend/data/src/main/kotlin/io/tolgee/model/views/activity/SimpleModifiedEntityView.kt b/backend/data/src/main/kotlin/io/tolgee/model/views/activity/SimpleModifiedEntityView.kt new file mode 100644 index 0000000000..b04287a8df --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/model/views/activity/SimpleModifiedEntityView.kt @@ -0,0 +1,29 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.model.views.activity + +import io.tolgee.activity.data.ExistenceEntityDescription +import io.tolgee.activity.data.PropertyModification + +data class SimpleModifiedEntityView( + val entityClass: String, + val entityId: Long, + val exists: Boolean?, + var modifications: Map = mutableMapOf(), + var description: Map? = null, + var describingRelations: Map? = null, +) diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt index 27144a35f1..cdf2db5d57 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt @@ -16,13 +16,103 @@ package io.tolgee.notifications +import io.tolgee.exceptions.NotFoundException +import io.tolgee.model.Project +import io.tolgee.model.UserAccount +import io.tolgee.model.notifications.NotificationPreferences +import io.tolgee.notifications.dto.NotificationPreferencesDto import io.tolgee.repository.notifications.NotificationPreferencesRepository +import io.tolgee.service.security.SecurityService import org.springframework.stereotype.Service +import javax.persistence.EntityManager @Service class NotificationPreferencesService( + private val entityManager: EntityManager, private val notificationPreferencesRepository: NotificationPreferencesRepository, + private val securityService: SecurityService, ) { + fun getAllPreferences(user: Long): Map { + return notificationPreferencesRepository.findAllByUserAccountId(user) + .associate { + val key = it.project?.id?.toString() ?: "global" + val dto = NotificationPreferencesDto.fromEntity(it) + Pair(key, dto) + } + } + + fun getGlobalPreferences(user: Long): NotificationPreferencesDto { + val entity = notificationPreferencesRepository.findByUserAccountIdAndProjectId(user, null) + ?: return NotificationPreferencesDto.createBlank() + + return NotificationPreferencesDto.fromEntity(entity) + } + + fun getProjectPreferences(user: Long, project: Long): NotificationPreferencesDto { + // If the user cannot see the project, the project "does not exist". + val scopes = securityService.getProjectPermissionScopes(project, user) ?: emptyArray() + if (scopes.isEmpty()) throw NotFoundException() + + val entity = notificationPreferencesRepository.findByUserAccountIdAndProjectId(user, null) + ?: throw NotFoundException() + + return NotificationPreferencesDto.fromEntity(entity) + } + + fun setPreferencesOfUser(user: Long, dto: NotificationPreferencesDto): NotificationPreferences { + return setPreferencesOfUser( + entityManager.getReference(UserAccount::class.java, user), + dto, + ) + } + + fun setPreferencesOfUser(user: UserAccount, dto: NotificationPreferencesDto): NotificationPreferences { + return doSetPreferencesOfUser(user, null, dto) + } + + fun setProjectPreferencesOfUser( + user: Long, + project: Long, + dto: NotificationPreferencesDto, + ): NotificationPreferences { + return setProjectPreferencesOfUser( + entityManager.getReference(UserAccount::class.java, user), + entityManager.getReference(Project::class.java, project), + dto, + ) + } + + fun setProjectPreferencesOfUser( + user: UserAccount, + project: Project, + dto: NotificationPreferencesDto, + ): NotificationPreferences { + // If the user cannot see the project, the project "does not exist". + val scopes = securityService.getProjectPermissionScopes(project.id, user.id) ?: emptyArray() + if (scopes.isEmpty()) throw NotFoundException() + + return doSetPreferencesOfUser(user, project, dto) + } + + private fun doSetPreferencesOfUser( + user: UserAccount, + project: Project?, + dto: NotificationPreferencesDto, + ): NotificationPreferences { + // Hidden as a private function as the fact global prefs and project overrides are the "same" is an implementation + // detail that should not be relied on by consumer of this service. + return notificationPreferencesRepository.save( + NotificationPreferences( + user, + project, + dto.disabledNotifications.toTypedArray(), + ) + ) + } + + fun deleteProjectPreferencesOfUser(user: Long, project: Long) { + notificationPreferencesRepository.deleteByUserAccountIdAndProjectId(user, project) + } fun deleteAllByUserId(userId: Long) { notificationPreferencesRepository.deleteAllByUserId(userId) diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationStatus.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationStatus.kt new file mode 100644 index 0000000000..157c985e65 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationStatus.kt @@ -0,0 +1,21 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.notifications + +enum class NotificationStatus { + UNREAD, READ, DONE +} diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt index 49c8a40a8a..51ebf35efb 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt @@ -16,7 +16,6 @@ package io.tolgee.notifications -import io.tolgee.model.UserAccount import io.tolgee.model.notifications.UserNotification import io.tolgee.notifications.dto.NotificationCreateDto import io.tolgee.notifications.dto.UserNotificationParamsDto @@ -40,54 +39,66 @@ class UserNotificationService( @Transactional fun dispatchNotifications(notificationDto: NotificationCreateDto, params: List) { - val userNotificationObjects = mutableSetOf() + val createdUserNotificationObjects = mutableSetOf() + val updatedUserNotificationObjects = mutableSetOf() val (processed, remaining) = userNotificationDebouncer.debounce(notificationDto, params) - userNotificationObjects.addAll( + updatedUserNotificationObjects.addAll( userNotificationRepository.saveAll(processed) ) remaining.forEach { val notification = notificationDto.toUserNotificationEntity(it) - userNotificationObjects.add( + createdUserNotificationObjects.add( userNotificationRepository.save(notification) ) } // Dispatch event applicationEventPublisher.publishEvent( - UserNotificationPushEvent(userNotificationObjects) + UserNotificationPushEvent( + createdUserNotificationObjects, + updatedUserNotificationObjects, + ) ) } - fun getNotificationsNotDone(user: UserAccount, pageable: Pageable): Collection { - return userNotificationRepository.findAllByMarkedDoneAtNullAndRecipient(user, pageable) + fun findNotificationsOfUserFilteredPaged( + user: Long, + status: Set, + pageable: Pageable, + ): List { + return userNotificationRepository.findNotificationsOfUserFilteredPaged(user, status, pageable) } - fun getNotificationsDone(user: UserAccount, pageable: Pageable): Collection { - return userNotificationRepository.findAllByMarkedDoneAtNotNullAndRecipient(user, pageable) + fun getUnreadNotificationsCount(user: Long): Int { + return userNotificationRepository.countNotificationsByRecipientIdAndUnreadTrue(user) } - fun getUnreadNotificationsCount(user: UserAccount): Int { - return userNotificationRepository.countNotificationsByRecipientAndUnreadTrue(user) + fun markAsRead(user: Long, notifications: Collection) { + return userNotificationRepository.markAsRead(user, notifications) } - fun markAsRead(user: UserAccount, notifications: Set) { + fun markAllAsRead(user: Long) { return userNotificationRepository.markAllAsRead(user) } - fun markAllAsRead(user: UserAccount) { - return userNotificationRepository.markAllAsRead(user) + fun markAsUnread(user: Long, notifications: Collection) { + return userNotificationRepository.markAsUnread(user, notifications) } - fun markAsDone(user: UserAccount, notifications: Set) { - return userNotificationRepository.markAllAsDone(user) + fun markAsDone(user: Long, notifications: Collection) { + return userNotificationRepository.markAsDone(user, notifications) } - fun markAllAsDone(user: UserAccount) { + fun markAllAsDone(user: Long) { return userNotificationRepository.markAllAsDone(user) } + fun unmarkAsDone(user: Long, notifications: Collection) { + return userNotificationRepository.unmarkAsDone(user, notifications) + } + fun deleteAllByUserId(userId: Long) { userNotificationRepository.deleteAllByUserId(userId) } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt index a5f6bbaed3..0ac6a6e4db 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt @@ -33,7 +33,7 @@ data class NotificationCreateDto( type = type, recipient = params.recipient, project = project, - modifiedEntities = params.modifiedEntities.toMutableSet() + modifiedEntities = params.modifiedEntities.toMutableList() ) } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationPreferencesDto.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationPreferencesDto.kt new file mode 100644 index 0000000000..7698de36ad --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationPreferencesDto.kt @@ -0,0 +1,38 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.notifications.dto + +import io.swagger.v3.oas.annotations.media.Schema +import io.tolgee.model.notifications.NotificationPreferences +import io.tolgee.notifications.NotificationType + +data class NotificationPreferencesDto( + @Schema(description = "List of notification types the user does not want to receive.") + val disabledNotifications: List +) { + companion object { + fun fromEntity(notificationPreferences: NotificationPreferences): NotificationPreferencesDto { + return NotificationPreferencesDto( + notificationPreferences.disabledNotifications.toList(), + ) + } + + fun createBlank(): NotificationPreferencesDto { + return NotificationPreferencesDto(emptyList()) + } + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/events/UserNotificationPushEvent.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/events/UserNotificationPushEvent.kt index 2e416245ad..980aeec1b5 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/events/UserNotificationPushEvent.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/events/UserNotificationPushEvent.kt @@ -21,4 +21,7 @@ import io.tolgee.model.notifications.UserNotification /** * Event sent when a set of users received a new notification. */ -data class UserNotificationPushEvent(val notifications: Set) +data class UserNotificationPushEvent( + val createdNotifications: Set, + val updatedNotifications: Set, +) diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/notifications/NotificationPreferencesRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/notifications/NotificationPreferencesRepository.kt index 536131c07d..8ba4e98896 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/notifications/NotificationPreferencesRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/notifications/NotificationPreferencesRepository.kt @@ -24,6 +24,12 @@ import org.springframework.stereotype.Repository @Repository interface NotificationPreferencesRepository : JpaRepository { + fun findAllByUserAccountId(user: Long): List + + fun findByUserAccountIdAndProjectId(user: Long, project: Long?): NotificationPreferences? + + fun deleteByUserAccountIdAndProjectId(user: Long, project: Long) + @Modifying @Query("DELETE FROM NotificationPreferences WHERE userAccount.id = :userId") fun deleteAllByUserId(userId: Long) diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt index 2583b1c05f..80b837a1aa 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt @@ -19,6 +19,7 @@ package io.tolgee.repository.notifications import io.tolgee.model.Project import io.tolgee.model.UserAccount import io.tolgee.model.notifications.UserNotification +import io.tolgee.notifications.NotificationStatus import io.tolgee.notifications.NotificationType import org.springframework.data.domain.Pageable import org.springframework.data.jpa.repository.JpaRepository @@ -30,11 +31,24 @@ import org.springframework.stereotype.Repository interface UserNotificationRepository : JpaRepository { fun findAllByRecipient(recipient: UserAccount): List - fun findAllByMarkedDoneAtNullAndRecipient(recipient: UserAccount, pageable: Pageable): List + fun countNotificationsByRecipientIdAndUnreadTrue(recipient: Long): Int - fun findAllByMarkedDoneAtNotNullAndRecipient(recipient: UserAccount, pageable: Pageable): List - - fun countNotificationsByRecipientAndUnreadTrue(recipient: UserAccount): Int + @Query( + """ + FROM UserNotification un WHERE + (io.tolgee.notifications.NotificationStatus.UNREAD IN :status AND + un.unread = true AND un.markedDoneAt IS NULL) OR + (io.tolgee.notifications.NotificationStatus.READ IN :status AND + un.unread = false AND un.markedDoneAt IS NULL) OR + (io.tolgee.notifications.NotificationStatus.DONE IN :status AND + un.markedDoneAt IS NOT NULL) + """ + ) + fun findNotificationsOfUserFilteredPaged( + recipient: Long, + status: Set, + pageable: Pageable, + ): List @Query( """ @@ -103,34 +117,34 @@ interface UserNotificationRepository : JpaRepository { ): List @Modifying - @Query("UPDATE UserNotification un SET un.unread = false WHERE un.recipient = ?1 AND un.id IN ?2") - fun markAsRead(recipient: UserAccount, notifications: Collection) - - @Modifying - @Query("UPDATE UserNotification un SET un.unread = false WHERE un.recipient = ?1") - fun markAllAsRead(recipient: UserAccount) + @Query("UPDATE UserNotification un SET un.unread = false WHERE un.recipient.id = ?1 AND un.id IN ?2") + fun markAsRead(recipient: Long, notifications: Collection) @Modifying - @Query("UPDATE UserNotification un SET un.unread = true WHERE un.recipient = ?1 AND un.id IN ?2") - fun markAsUnread(recipient: UserAccount, notifications: Collection) + @Query("UPDATE UserNotification un SET un.unread = false WHERE un.recipient.id = ?1") + fun markAllAsRead(recipient: Long) @Modifying - @Query("UPDATE UserNotification un SET un.unread = true WHERE un.recipient = ?1") - fun markAllAsUnread(recipient: UserAccount) + @Query("UPDATE UserNotification un SET un.unread = true WHERE un.recipient.id = ?1 AND un.id IN ?2") + fun markAsUnread(recipient: Long, notifications: Collection) @Modifying @Query( - "UPDATE UserNotification un SET un.unread = false, un.markedDoneAt = NOW() WHERE un.recipient = ?1 AND un.id IN ?2" + """ + UPDATE UserNotification un + SET un.unread = false, un.markedDoneAt = NOW() + WHERE un.recipient.id = ?1 AND un.id IN ?2 + """ ) - fun markAsDone(recipient: UserAccount, notifications: Collection) + fun markAsDone(recipient: Long, notifications: Collection) @Modifying - @Query("UPDATE UserNotification un SET un.unread = false, un.markedDoneAt = NOW() WHERE un.recipient = ?1") - fun markAllAsDone(recipient: UserAccount) + @Query("UPDATE UserNotification un SET un.unread = false, un.markedDoneAt = NOW() WHERE un.recipient.id = ?1") + fun markAllAsDone(recipient: Long) @Modifying - @Query("UPDATE UserNotification un SET un.markedDoneAt = null WHERE un.recipient = ?1 AND un.id IN ?2") - fun unmarkAsDone(recipient: UserAccount, notifications: Collection) + @Query("UPDATE UserNotification un SET un.markedDoneAt = null WHERE un.recipient.id = ?1 AND un.id IN ?2") + fun unmarkAsDone(recipient: Long, notifications: Collection) @Modifying @Query("DELETE FROM user_notification WHERE marked_done_at < NOW() - INTERVAL '90 DAY'", nativeQuery = true) From 4aebb9401e22a7c74ba5e5ae27068ed84a8c29b3 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Wed, 13 Dec 2023 16:21:58 +0100 Subject: [PATCH 20/44] fix: notification updates --- .../notifications/NotificationsController.kt | 2 +- .../UserNotificationTranslationTest.kt | 1 - .../development/testDataBuilder/TestDataService.kt | 2 +- .../notifications/UserNotificationService.kt | 14 +++++++++++++- .../notifications/UserNotificationRepository.kt | 14 ++++++-------- .../e2e_data/NotificationsE2eDataController.kt | 14 ++++++++++++++ 6 files changed, 35 insertions(+), 12 deletions(-) diff --git a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationsController.kt b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationsController.kt index e9182da6e1..aecac369c9 100644 --- a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationsController.kt +++ b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationsController.kt @@ -42,7 +42,7 @@ class NotificationsController( private val userNotificationService: UserNotificationService, private val userNotificationModelAssembler: UserNotificationModelAssembler, ) { - @GetMapping("/") + @GetMapping("") @Operation(summary = "Fetch the current user's notifications") fun getNotifications( @RequestParam("status", defaultValue = "UNREAD,READ") status: Set, diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationTranslationTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationTranslationTest.kt index 85e133137c..936f458510 100644 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationTranslationTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationTranslationTest.kt @@ -86,7 +86,6 @@ class UserNotificationTranslationTest : AbstractNotificationTest() { waitUntilUserNotificationDispatch() - println(userNotificationRepository.findAllByRecipient(testData.alice).map { it.type }) userNotificationRepository.findAllByRecipient(testData.alice).assert.hasSize(1) } diff --git a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/TestDataService.kt b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/TestDataService.kt index e512c691aa..6c7ac282a7 100644 --- a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/TestDataService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/TestDataService.kt @@ -346,7 +346,7 @@ class TestDataService( } private fun saveAllKeyDependants(keyBuilders: List) { - val metas = keyBuilders.map { it.data.meta?.self }.filterNotNull() + val metas = keyBuilders.mapNotNull { it.data.meta?.self } tagService.saveAll(metas.flatMap { it.tags }) keyMetaService.saveAll(metas) } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt index 51ebf35efb..5487c1e516 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt @@ -68,41 +68,53 @@ class UserNotificationService( status: Set, pageable: Pageable, ): List { - return userNotificationRepository.findNotificationsOfUserFilteredPaged(user, status, pageable) + return userNotificationRepository.findNotificationsOfUserFilteredPaged( + user, + status.map { it.toString() }, + pageable, + ) } fun getUnreadNotificationsCount(user: Long): Int { return userNotificationRepository.countNotificationsByRecipientIdAndUnreadTrue(user) } + @Transactional fun markAsRead(user: Long, notifications: Collection) { return userNotificationRepository.markAsRead(user, notifications) } + @Transactional fun markAllAsRead(user: Long) { return userNotificationRepository.markAllAsRead(user) } + @Transactional fun markAsUnread(user: Long, notifications: Collection) { return userNotificationRepository.markAsUnread(user, notifications) } + @Transactional fun markAsDone(user: Long, notifications: Collection) { return userNotificationRepository.markAsDone(user, notifications) } + @Transactional fun markAllAsDone(user: Long) { return userNotificationRepository.markAllAsDone(user) } + @Transactional fun unmarkAsDone(user: Long, notifications: Collection) { return userNotificationRepository.unmarkAsDone(user, notifications) } + @Transactional fun deleteAllByUserId(userId: Long) { userNotificationRepository.deleteAllByUserId(userId) } + @Transactional fun deleteAllByProjectId(projectId: Long) { userNotificationRepository.deleteAllByProjectId(projectId) } diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt index 80b837a1aa..4fc2b871c7 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt @@ -19,7 +19,6 @@ package io.tolgee.repository.notifications import io.tolgee.model.Project import io.tolgee.model.UserAccount import io.tolgee.model.notifications.UserNotification -import io.tolgee.notifications.NotificationStatus import io.tolgee.notifications.NotificationType import org.springframework.data.domain.Pageable import org.springframework.data.jpa.repository.JpaRepository @@ -36,17 +35,16 @@ interface UserNotificationRepository : JpaRepository { @Query( """ FROM UserNotification un WHERE - (io.tolgee.notifications.NotificationStatus.UNREAD IN :status AND - un.unread = true AND un.markedDoneAt IS NULL) OR - (io.tolgee.notifications.NotificationStatus.READ IN :status AND - un.unread = false AND un.markedDoneAt IS NULL) OR - (io.tolgee.notifications.NotificationStatus.DONE IN :status AND - un.markedDoneAt IS NOT NULL) + un.recipient.id = :recipient AND ( + ('UNREAD' IN :status AND un.unread = true AND un.markedDoneAt IS NULL) OR + ('READ' IN :status AND un.unread = false AND un.markedDoneAt IS NULL) OR + ('DONE' IN :status AND un.markedDoneAt IS NOT NULL) + ) """ ) fun findNotificationsOfUserFilteredPaged( recipient: Long, - status: Set, + status: List, pageable: Pageable, ): List diff --git a/backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2e_data/NotificationsE2eDataController.kt b/backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2e_data/NotificationsE2eDataController.kt index ac3f556a49..86455df2e9 100644 --- a/backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2e_data/NotificationsE2eDataController.kt +++ b/backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2e_data/NotificationsE2eDataController.kt @@ -19,6 +19,9 @@ package io.tolgee.controllers.internal.e2e_data import io.swagger.v3.oas.annotations.Hidden import io.tolgee.development.testDataBuilder.builders.TestDataBuilder import io.tolgee.development.testDataBuilder.data.NotificationsTestData +import io.tolgee.repository.UserAccountRepository +import io.tolgee.service.security.UserAccountService +import org.springframework.beans.factory.annotation.Autowired import org.springframework.transaction.annotation.Transactional import org.springframework.web.bind.annotation.CrossOrigin import org.springframework.web.bind.annotation.GetMapping @@ -30,9 +33,20 @@ import org.springframework.web.bind.annotation.RestController @Hidden @RequestMapping(value = ["internal/e2e-data/notifications"]) class NotificationsE2eDataController : AbstractE2eDataController() { + @Autowired + lateinit var userAccountRepository: UserAccountRepository + + @Autowired + lateinit var userAccountService: UserAccountService + @GetMapping(value = ["/generate"]) @Transactional fun generateBasicTestData() { + userAccountService.findActive("admin")?.let { + userAccountService.delete(it) + userAccountRepository.delete(it) + } + testDataService.saveTestData(testData) } From 38e938a3e85ad714675dee2ba054f608b8ad72ef Mon Sep 17 00:00:00 2001 From: Cynthia Date: Wed, 13 Dec 2023 18:05:54 +0100 Subject: [PATCH 21/44] fix: key creation test --- .../v2/controllers/v2KeyController/KeyControllerCreationTest.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2KeyController/KeyControllerCreationTest.kt b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2KeyController/KeyControllerCreationTest.kt index 2f0c3249e3..c9aac59461 100644 --- a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2KeyController/KeyControllerCreationTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2KeyController/KeyControllerCreationTest.kt @@ -21,6 +21,7 @@ import io.tolgee.testing.annotations.ProjectApiKeyAuthTestMethod import io.tolgee.testing.annotations.ProjectJWTAuthTestMethod import io.tolgee.testing.assert import io.tolgee.testing.assertions.Assertions.assertThat +import io.tolgee.testing.satisfies import io.tolgee.util.generateImage import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test From 1d54b2e8f506f5a9036bd0678ed83ce383a465a6 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Fri, 26 Jan 2024 12:19:51 +0100 Subject: [PATCH 22/44] fix: migrate notifications to Spring Boot 3 --- .../NotificationPreferencesController.kt | 34 ++-- .../notifications/NotificationsController.kt | 29 ++- .../UserNotificationModelAssembler.kt | 23 ++- .../hateoas/project/ProjectModelAssembler.kt | 2 +- .../notifications/AbstractNotificationTest.kt | 5 +- .../RemappedNotificationsTest.kt | 64 +++--- .../UserNotificationDebounceTest.kt | 33 +-- .../UserNotificationDispatchTest.kt | 37 ++-- .../UserNotificationSubscriptionTest.kt | 4 +- .../UserNotificationTranslationTest.kt | 38 ++-- .../views/ActivityViewByRevisionsProvider.kt | 15 +- .../views/ModifiedEntitiesViewProvider.kt | 25 +-- .../NotificationPreferencesBuilder.kt | 2 +- .../builders/UserAccountBuilder.kt | 3 +- .../data/NotificationSubscriptionTestData.kt | 22 +- .../data/NotificationsTestData.kt | 27 +-- .../dtos/request/key/KeyScreenshotDto.kt | 1 - .../main/kotlin/io/tolgee/model/Permission.kt | 27 ++- .../kotlin/io/tolgee/model/UserAccount.kt | 1 - .../notifications/NotificationPreferences.kt | 43 ++-- .../model/notifications/UserNotification.kt | 38 ++-- ...missionsNotificationPreferencesDataView.kt | 78 ++++++-- .../model/views/UserProjectMetadataView.kt | 40 ++++ .../NotificationPreferencesService.kt | 34 +++- .../notifications/NotificationStatus.kt | 4 +- .../tolgee/notifications/NotificationType.kt | 34 ++-- .../UserNotificationDebouncer.kt | 90 +++++---- .../notifications/UserNotificationService.kt | 40 +++- .../dispatchers/UserNotificationDispatch.kt | 79 ++++---- .../dto/NotificationCreateDto.kt | 16 +- .../dto/NotificationPreferencesDto.kt | 2 +- .../dto/UserNotificationParamsDto.kt | 2 +- .../events/NotificationCreateEvent.kt | 6 +- .../listeners/ActivityEventListener.kt | 189 +++++++++--------- .../listeners/BatchJobListener.kt | 9 +- .../tolgee/repository/LanguageRepository.kt | 6 +- .../repository/UserAccountRepository.kt | 29 ++- .../NotificationPreferencesRepository.kt | 10 +- .../UserNotificationRepository.kt | 52 +++-- .../io/tolgee/service/LanguageService.kt | 5 +- .../tolgee/service/project/ProjectService.kt | 4 +- .../service/security/PermissionService.kt | 37 +--- .../service/security/UserAccountService.kt | 12 +- .../e2eData/NotificationsE2eDataController.kt | 2 +- .../io/tolgee/fixtures/statusExpectations.kt | 2 +- .../kotlin/io/tolgee/testing/satisfies.kt | 8 +- 46 files changed, 720 insertions(+), 543 deletions(-) create mode 100644 backend/data/src/main/kotlin/io/tolgee/model/views/UserProjectMetadataView.kt diff --git a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationPreferencesController.kt b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationPreferencesController.kt index 0aa3c3ec35..53c75fe6ff 100644 --- a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationPreferencesController.kt +++ b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationPreferencesController.kt @@ -59,17 +59,20 @@ class NotificationPreferencesController( fun updateGlobalPreferences( @RequestBody @Validated preferencesDto: NotificationPreferencesDto, ): NotificationPreferencesDto { - val updated = notificationPreferencesService.setPreferencesOfUser( - authenticationFacade.authenticatedUser.id, - preferencesDto, - ) + val updated = + notificationPreferencesService.setPreferencesOfUser( + authenticationFacade.authenticatedUser.id, + preferencesDto, + ) return NotificationPreferencesDto.fromEntity(updated) } @GetMapping("/project/{id}") @Operation(summary = "Fetch the notification preferences of the current user for a specific project") - fun getPerProjectPreferences(@PathVariable("id") id: Long): NotificationPreferencesDto { + fun getPerProjectPreferences( + @PathVariable("id") id: Long, + ): NotificationPreferencesDto { return notificationPreferencesService.getProjectPreferences( authenticationFacade.authenticatedUser.id, id, @@ -82,11 +85,12 @@ class NotificationPreferencesController( @PathVariable("id") id: Long, @RequestBody @Validated preferencesDto: NotificationPreferencesDto, ): NotificationPreferencesDto { - val updated = notificationPreferencesService.setProjectPreferencesOfUser( - authenticationFacade.authenticatedUser.id, - id, - preferencesDto, - ) + val updated = + notificationPreferencesService.setProjectPreferencesOfUser( + authenticationFacade.authenticatedUser.id, + id, + preferencesDto, + ) return NotificationPreferencesDto.fromEntity(updated) } @@ -94,7 +98,9 @@ class NotificationPreferencesController( @DeleteMapping("/project/{id}") @ResponseStatus(HttpStatus.NO_CONTENT) @Operation(summary = "Delete the notification preferences of the current user for a specific project") - fun deletePerProjectPreferences(@PathVariable("id") id: Long) { + fun deletePerProjectPreferences( + @PathVariable("id") id: Long, + ) { notificationPreferencesService.deleteProjectPreferencesOfUser( authenticationFacade.authenticatedUser.id, id, @@ -103,7 +109,9 @@ class NotificationPreferencesController( @PostMapping("/project/{id}/subscribe") @Operation(summary = "Subscribe to notifications for a given project") - fun subscribeToProject(@PathVariable("id") id: Long): ResponseEntity { + fun subscribeToProject( + @PathVariable("id") id: Long, + ): ResponseEntity { return ResponseEntity( "Coming soon! Please see https://github.com/tolgee/tolgee-platform/issues/1360 for progress on this. :D", HttpHeaders().also { @@ -111,7 +119,7 @@ class NotificationPreferencesController( it.add( "x-hey-curious-reader", "oh hey there, didn't expect you here... " + - "if you're here, might as well join us! https://tolgee.io/career" + "if you're here, might as well join us! https://tolgee.io/career", ) }, HttpStatus.NOT_IMPLEMENTED, diff --git a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationsController.kt b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationsController.kt index aecac369c9..426f651835 100644 --- a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationsController.kt +++ b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationsController.kt @@ -23,7 +23,7 @@ import io.tolgee.hateoas.notifications.UserNotificationModelAssembler import io.tolgee.notifications.NotificationStatus import io.tolgee.notifications.UserNotificationService import io.tolgee.security.authentication.AuthenticationFacade -import org.springdoc.api.annotations.ParameterObject +import org.springdoc.core.annotations.ParameterObject import org.springframework.data.domain.Pageable import org.springframework.http.HttpStatus import org.springframework.web.bind.annotation.GetMapping @@ -48,11 +48,12 @@ class NotificationsController( @RequestParam("status", defaultValue = "UNREAD,READ") status: Set, @ParameterObject pageable: Pageable, ): List { - val notifications = userNotificationService.findNotificationsOfUserFilteredPaged( - authenticationFacade.authenticatedUser.id, - status, - pageable, - ) + val notifications = + userNotificationService.findNotificationsOfUserFilteredPaged( + authenticationFacade.authenticatedUser.id, + status, + pageable, + ) return notifications.map { userNotificationModelAssembler.toModel(it) } } @@ -60,7 +61,9 @@ class NotificationsController( @PostMapping("/mark-as-read") @ResponseStatus(HttpStatus.NO_CONTENT) @Operation(summary = "Marks a given set of notifications as read.") - fun markNotificationsAsRead(@RequestBody notifications: List) { + fun markNotificationsAsRead( + @RequestBody notifications: List, + ) { userNotificationService.markAsRead( authenticationFacade.authenticatedUser.id, notifications, @@ -77,7 +80,9 @@ class NotificationsController( @PostMapping("/mark-as-unread") @ResponseStatus(HttpStatus.NO_CONTENT) @Operation(summary = "Marks a given set of notifications as unread.") - fun markNotificationsAsUnread(@RequestBody notifications: List) { + fun markNotificationsAsUnread( + @RequestBody notifications: List, + ) { userNotificationService.markAsUnread( authenticationFacade.authenticatedUser.id, notifications, @@ -87,7 +92,9 @@ class NotificationsController( @PostMapping("/mark-as-done") @ResponseStatus(HttpStatus.NO_CONTENT) @Operation(summary = "Marks a given set of notifications as done.") - fun markNotificationsAsDone(@RequestBody notifications: List) { + fun markNotificationsAsDone( + @RequestBody notifications: List, + ) { userNotificationService.markAsDone( authenticationFacade.authenticatedUser.id, notifications, @@ -104,7 +111,9 @@ class NotificationsController( @PostMapping("/unmark-as-done") @ResponseStatus(HttpStatus.NO_CONTENT) @Operation(summary = "Un-marks a given set of notifications as done.") - fun unmarkNotificationsAsDone(@RequestBody notifications: Collection) { + fun unmarkNotificationsAsDone( + @RequestBody notifications: Collection, + ) { userNotificationService.unmarkAsDone( authenticationFacade.authenticatedUser.id, notifications, diff --git a/backend/api/src/main/kotlin/io/tolgee/hateoas/notifications/UserNotificationModelAssembler.kt b/backend/api/src/main/kotlin/io/tolgee/hateoas/notifications/UserNotificationModelAssembler.kt index 67e8013471..1502f11f10 100644 --- a/backend/api/src/main/kotlin/io/tolgee/hateoas/notifications/UserNotificationModelAssembler.kt +++ b/backend/api/src/main/kotlin/io/tolgee/hateoas/notifications/UserNotificationModelAssembler.kt @@ -35,15 +35,17 @@ class UserNotificationModelAssembler( private val batchJobModelAssembler: BatchJobModelAssembler, private val applicationContext: ApplicationContext, ) : RepresentationModelAssemblerSupport( - NotificationsController::class.java, UserNotificationModel::class.java -) { + NotificationsController::class.java, + UserNotificationModel::class.java, + ) { override fun toModel(entity: UserNotification): UserNotificationModel { val project = entity.project?.let { simpleProjectModelAssembler.toModel(it) } val modifiedEntities = assembleEntityChanges(entity.modifiedEntities).ifEmpty { null } - val batchJob = entity.batchJob?.let { - val view = batchJobService.getView(it) - batchJobModelAssembler.toModel(view) - } + val batchJob = + entity.batchJob?.let { + val view = batchJobService.getView(it) + batchJobModelAssembler.toModel(view) + } return UserNotificationModel( id = entity.id, @@ -58,10 +60,11 @@ class UserNotificationModelAssembler( } private fun assembleEntityChanges(modifiedEntities: List): List { - val provider = ModifiedEntitiesViewProvider( - applicationContext, - modifiedEntities - ) + val provider = + ModifiedEntitiesViewProvider( + applicationContext, + modifiedEntities, + ) return provider.getSimple() } diff --git a/backend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectModelAssembler.kt b/backend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectModelAssembler.kt index 34d6fea070..d93dc0cac1 100644 --- a/backend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectModelAssembler.kt +++ b/backend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectModelAssembler.kt @@ -49,7 +49,7 @@ class ProjectModelAssembler( avatar = avatarService.getAvatarLinks(view.avatarHash), organizationRole = view.organizationRole, organizationOwner = view.organizationOwner.let { simpleOrganizationModelAssembler.toModel(it) }, - baseLanguage = baseLanguage?.let { languageModelAssembler.toModel(LanguageDto.fromEntity(it, it.id)) }, + baseLanguage = baseLanguage.let { languageModelAssembler.toModel(LanguageDto.fromEntity(it, it.id)) }, directPermission = view.directPermission?.let { permissionModelAssembler.toModel(it) }, computedPermission = computedPermissionModelAssembler.toModel(computedPermissions), ).add(link).also { model -> diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt index 1eb68e4c12..79288afb14 100644 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt @@ -55,11 +55,12 @@ abstract class AbstractNotificationTest : AuthorizedControllerTest() { entityManager.refresh(it.arguments[0]) + println("Dispatched!") // Wait a bit to make sure everything's *actually* persisted // Kind of an ugly way to synchronize everything, but it is what it is taskScheduler.schedule( { semaphore.release() }, - Date().addMilliseconds(100) + Date().addMilliseconds(100), ) it.arguments[0] @@ -76,7 +77,7 @@ abstract class AbstractNotificationTest : AuthorizedControllerTest() { // Kind of an ugly way to synchronize everything, but it is what it is taskScheduler.schedule( { semaphore.release(list.size) }, - Date().addMilliseconds(100) + Date().addMilliseconds(100), ) it.arguments[0] diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/RemappedNotificationsTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/RemappedNotificationsTest.kt index b00b503e18..e11f111477 100644 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/RemappedNotificationsTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/RemappedNotificationsTest.kt @@ -43,20 +43,27 @@ class RemappedNotificationsTest : AbstractNotificationTest() { fun `it does properly remap imports to key and translation notifications`() { performAuthMultipart( url = "/v2/projects/${testData.project1.id}/import", - files = listOf( - MockMultipartFile( - "files", "en.json", "application/json", - """{"new-key1": "New string 1", "new-key2": "New string 2"}""".toByteArray() + files = + listOf( + MockMultipartFile( + "files", + "en.json", + "application/json", + """{"new-key1": "New string 1", "new-key2": "New string 2"}""".toByteArray(), + ), + MockMultipartFile( + "files", + "fr.json", + "application/json", + """{"some-key": "Updated", "new-key1": "New FR string 1", "new-key2": "New FR string 2"}""".toByteArray(), + ), + MockMultipartFile( + "files", + "cs.json", + "application/json", + """{"new-key1": "New CZ string 1", "new-key2": "New CZ string 2"}""".toByteArray(), + ), ), - MockMultipartFile( - "files", "fr.json", "application/json", - """{"some-key": "Updated", "new-key1": "New FR string 1", "new-key2": "New FR string 2"}""".toByteArray() - ), - MockMultipartFile( - "files", "cs.json", "application/json", - """{"new-key1": "New CZ string 1", "new-key2": "New CZ string 2"}""".toByteArray() - ) - ) ).andIsOk performAuthPut("/v2/projects/${testData.project1.id}/import/apply?forceMode=OVERRIDE", null).andIsOk @@ -155,15 +162,19 @@ class RemappedNotificationsTest : AbstractNotificationTest() { @Test fun `it does remap complex key edits to relevant notification types`() { - val screenshotId = performAuthMultipart( - url = "/v2/image-upload", - files = listOf( - MockMultipartFile( - "image", "image.png", "image/png", - generateImage(100, 100).inputStream.readAllBytes() - ) - ) - ).andIsCreated.andGetContentAsJsonMap["id"].let { (it as Int).toLong() } + val screenshotId = + performAuthMultipart( + url = "/v2/image-upload", + files = + listOf( + MockMultipartFile( + "image", + "image.png", + "image/png", + generateImage(100, 100).inputStream.readAllBytes(), + ), + ), + ).andIsCreated.andGetContentAsJsonMap["id"].let { (it as Int).toLong() } performAuthPut( "/v2/projects/${testData.project1.id}/keys/${testData.keyProject1.id}/complex-update", @@ -171,10 +182,11 @@ class RemappedNotificationsTest : AbstractNotificationTest() { name = "new-name", namespace = "new-namespace", translations = mapOf("en" to "New EN string", "fr" to "New FR string"), - screenshotsToAdd = listOf( - KeyScreenshotDto(uploadedImageId = screenshotId) - ) - ) + screenshotsToAdd = + listOf( + KeyScreenshotDto(uploadedImageId = screenshotId), + ), + ), ).andIsOk waitUntilUserNotificationDispatch(25) diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt index 16142f28ea..fba8d75986 100644 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt @@ -17,7 +17,7 @@ package io.tolgee.notifications import io.tolgee.development.testDataBuilder.data.NotificationsTestData -import io.tolgee.dtos.request.LanguageDto +import io.tolgee.dtos.request.LanguageRequest import io.tolgee.dtos.request.key.CreateKeyDto import io.tolgee.dtos.request.translation.comment.TranslationCommentWithLangKeyDto import io.tolgee.fixtures.andIsCreated @@ -41,7 +41,7 @@ class UserNotificationDebounceTest : AbstractNotificationTest() { fun `it debounces notifications of the same type`() { performAuthPost( "/v2/projects/${testData.calmProject.id}/keys/create", - CreateKeyDto(name = "test-key-1") + CreateKeyDto(name = "test-key-1"), ).andIsCreated waitUntilUserNotificationDispatch() @@ -49,7 +49,7 @@ class UserNotificationDebounceTest : AbstractNotificationTest() { performAuthPost( "/v2/projects/${testData.calmProject.id}/keys/create", - CreateKeyDto(name = "test-key-2") + CreateKeyDto(name = "test-key-2"), ).andIsCreated waitUntilUserNotificationDispatch() @@ -57,11 +57,12 @@ class UserNotificationDebounceTest : AbstractNotificationTest() { performAuthPost( url = "/v2/projects/${testData.calmProject.id}/languages", - content = LanguageDto( - name = "Meow", - originalName = "meow", - tag = "meow-en", - ) + content = + LanguageRequest( + name = "Meow", + originalName = "meow", + tag = "meow-en", + ), ).andIsOk waitUntilUserNotificationDispatch() @@ -72,7 +73,7 @@ class UserNotificationDebounceTest : AbstractNotificationTest() { fun `it only debounces notifications within the same project`() { performAuthPost( "/v2/projects/${testData.calmProject.id}/keys/create", - CreateKeyDto(name = "test-key-1") + CreateKeyDto(name = "test-key-1"), ).andIsCreated waitUntilUserNotificationDispatch() @@ -80,7 +81,7 @@ class UserNotificationDebounceTest : AbstractNotificationTest() { performAuthPost( "/v2/projects/${testData.project2.id}/keys/create", - CreateKeyDto(name = "test-key-2") + CreateKeyDto(name = "test-key-2"), ).andIsCreated waitUntilUserNotificationDispatch() @@ -94,8 +95,8 @@ class UserNotificationDebounceTest : AbstractNotificationTest() { TranslationCommentWithLangKeyDto( keyId = testData.keyCalmProject.id, languageId = testData.keyCalmEnTranslation.language.id, - text = "This is a test" - ) + text = "This is a test", + ), ).andIsCreated waitUntilUserNotificationDispatch() @@ -106,8 +107,8 @@ class UserNotificationDebounceTest : AbstractNotificationTest() { TranslationCommentWithLangKeyDto( keyId = testData.keyCalmProject.id, languageId = testData.keyCalmEnTranslation.language.id, - text = "This is a test 2" - ) + text = "This is a test 2", + ), ).andIsCreated waitUntilUserNotificationDispatch() @@ -118,8 +119,8 @@ class UserNotificationDebounceTest : AbstractNotificationTest() { TranslationCommentWithLangKeyDto( keyId = testData.keyCalmProject.id, languageId = testData.calmProjectFr.id, - text = "This is a test" - ) + text = "This is a test", + ), ).andIsCreated waitUntilUserNotificationDispatch() diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDispatchTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDispatchTest.kt index 506e49c30a..e6a4296de0 100644 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDispatchTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDispatchTest.kt @@ -42,7 +42,7 @@ class UserNotificationDispatchTest : AbstractNotificationTest() { fun `it dispatches notifications to everyone in project`() { performAuthPost( "/v2/projects/${testData.project1.id}/keys/create", - CreateKeyDto(name = "test-key") + CreateKeyDto(name = "test-key"), ).andIsCreated waitUntilUserNotificationDispatch(7) @@ -74,12 +74,15 @@ class UserNotificationDispatchTest : AbstractNotificationTest() { fun `it does not dispatch notifications to people without the permission to see the change`() { performAuthMultipart( url = "/v2/projects/${testData.project1.id}/keys/${testData.keyProject1.id}/screenshots", - files = listOf( - MockMultipartFile( - "screenshot", "originalShot.png", "image/png", - generateImage(100, 100).inputStream.readAllBytes() - ) - ) + files = + listOf( + MockMultipartFile( + "screenshot", + "originalShot.png", + "image/png", + generateImage(100, 100).inputStream.readAllBytes(), + ), + ), ).andIsCreated waitUntilUserNotificationDispatch(6) @@ -107,10 +110,11 @@ class UserNotificationDispatchTest : AbstractNotificationTest() { fun `it does not dispatch notifications to people without the permission to see the target language`() { performAuthPut( url = "/v2/projects/${testData.project1.id}/translations", - content = SetTranslationsWithKeyDto( - key = testData.keyProject1.name, - translations = mapOf("fr" to "Superb French translation!") - ) + content = + SetTranslationsWithKeyDto( + key = testData.keyProject1.name, + translations = mapOf("fr" to "Superb French translation!"), + ), ).andIsOk waitUntilUserNotificationDispatch(5) @@ -138,10 +142,11 @@ class UserNotificationDispatchTest : AbstractNotificationTest() { fun `it does dispatch notifications with trimmed data to people who can only see part of the changes`() { performAuthPut( url = "/v2/projects/${testData.project1.id}/translations", - content = SetTranslationsWithKeyDto( - key = testData.keyProject1.name, - translations = mapOf("fr" to "Superb French translation!", "cs" to "Superb Czech translation!") - ) + content = + SetTranslationsWithKeyDto( + key = testData.keyProject1.name, + translations = mapOf("fr" to "Superb French translation!", "cs" to "Superb Czech translation!"), + ), ).andIsOk waitUntilUserNotificationDispatch(6) @@ -183,7 +188,7 @@ class UserNotificationDispatchTest : AbstractNotificationTest() { loginAsUser(testData.projectManager) performAuthPost( "/v2/projects/${testData.project1.id}/keys/create", - CreateKeyDto(name = "test-key") + CreateKeyDto(name = "test-key"), ).andIsCreated waitUntilUserNotificationDispatch(6) diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationSubscriptionTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationSubscriptionTest.kt index 669ecdcf6f..31c18c34e2 100644 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationSubscriptionTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationSubscriptionTest.kt @@ -38,7 +38,7 @@ class UserNotificationSubscriptionTest : AbstractNotificationTest() { fun `it respects global notification subscription settings`() { performAuthPost( "/v2/projects/${testData.project1.id}/keys/create", - CreateKeyDto(name = "test-key") + CreateKeyDto(name = "test-key"), ).andIsCreated waitUntilUserNotificationDispatch(1) @@ -54,7 +54,7 @@ class UserNotificationSubscriptionTest : AbstractNotificationTest() { fun `it respects project-level notification subscription settings`() { performAuthPost( "/v2/projects/${testData.project2.id}/keys/create", - CreateKeyDto(name = "test-key") + CreateKeyDto(name = "test-key"), ).andIsCreated waitUntilUserNotificationDispatch(1) diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationTranslationTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationTranslationTest.kt index 936f458510..d7a6b222e2 100644 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationTranslationTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationTranslationTest.kt @@ -40,10 +40,11 @@ class UserNotificationTranslationTest : AbstractNotificationTest() { fun `it does not dispatch the same type of notification for source strings and translated strings`() { performAuthPut( url = "/v2/projects/${testData.calmProject.id}/translations", - content = SetTranslationsWithKeyDto( - key = testData.keyCalmProject.name, - translations = mapOf("en" to "Superb English translation!") - ) + content = + SetTranslationsWithKeyDto( + key = testData.keyCalmProject.name, + translations = mapOf("en" to "Superb English translation!"), + ), ).andIsOk waitUntilUserNotificationDispatch() @@ -54,10 +55,11 @@ class UserNotificationTranslationTest : AbstractNotificationTest() { performAuthPut( url = "/v2/projects/${testData.calmProject.id}/translations", - content = SetTranslationsWithKeyDto( - key = testData.keyCalmProject.name, - translations = mapOf("fr" to "Superb French translation!") - ) + content = + SetTranslationsWithKeyDto( + key = testData.keyCalmProject.name, + translations = mapOf("fr" to "Superb French translation!"), + ), ).andIsOk waitUntilUserNotificationDispatch() @@ -71,17 +73,18 @@ class UserNotificationTranslationTest : AbstractNotificationTest() { fun `it does debounce key creation and setting strings as a single notification`() { performAuthPost( "/v2/projects/${testData.calmProject.id}/keys/create", - CreateKeyDto(name = "test-key") + CreateKeyDto(name = "test-key"), ).andIsCreated waitUntilUserNotificationDispatch() performAuthPut( url = "/v2/projects/${testData.calmProject.id}/translations", - content = SetTranslationsWithKeyDto( - key = "test-key", - translations = mapOf("en" to "Superb English translation!", "fr" to "Superb French translation!") - ) + content = + SetTranslationsWithKeyDto( + key = "test-key", + translations = mapOf("en" to "Superb English translation!", "fr" to "Superb French translation!"), + ), ).andIsOk waitUntilUserNotificationDispatch() @@ -93,10 +96,11 @@ class UserNotificationTranslationTest : AbstractNotificationTest() { fun `it does not dispatch outdated notifications if it was not done manually`() { performAuthPut( url = "/v2/projects/${testData.calmProject.id}/translations", - content = SetTranslationsWithKeyDto( - key = testData.keyCalmProject.name, - translations = mapOf("en" to "Superb English translation!") - ) + content = + SetTranslationsWithKeyDto( + key = testData.keyCalmProject.name, + translations = mapOf("en" to "Superb English translation!"), + ), ).andIsOk waitUntilUserNotificationDispatch() diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/views/ActivityViewByRevisionsProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/views/ActivityViewByRevisionsProvider.kt index 6b4e447919..f33ff4dc4d 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/views/ActivityViewByRevisionsProvider.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/views/ActivityViewByRevisionsProvider.kt @@ -10,7 +10,6 @@ import io.tolgee.model.views.activity.ModifiedEntityView import io.tolgee.model.views.activity.ProjectActivityView import io.tolgee.repository.activity.ActivityRevisionRepository import io.tolgee.service.security.UserAccountService -import io.tolgee.util.EntityUtil import jakarta.persistence.EntityManager import jakarta.persistence.criteria.Predicate import org.springframework.context.ApplicationContext @@ -65,13 +64,15 @@ class ActivityViewByRevisionsProvider( rawModifiedEntities = getModifiedEntitiesRaw() - val modifiedEntitiesViewProvider = ModifiedEntitiesViewProvider( - applicationContext, - rawModifiedEntities - ) + val modifiedEntitiesViewProvider = + ModifiedEntitiesViewProvider( + applicationContext, + rawModifiedEntities, + ) - modifiedEntities = modifiedEntitiesViewProvider.get() - .groupBy { it.activityRevision.id } + modifiedEntities = + modifiedEntitiesViewProvider.get() + .groupBy { it.activityRevision.id } params = getParams() diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/views/ModifiedEntitiesViewProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/views/ModifiedEntitiesViewProvider.kt index e4d04e92f5..f23b378d7e 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/views/ModifiedEntitiesViewProvider.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/views/ModifiedEntitiesViewProvider.kt @@ -28,12 +28,12 @@ import io.tolgee.model.views.activity.SimpleModifiedEntityView import io.tolgee.repository.activity.ActivityRevisionRepository import io.tolgee.service.security.UserAccountService import io.tolgee.util.EntityUtil +import jakarta.persistence.EntityManager import org.springframework.context.ApplicationContext -import javax.persistence.EntityManager class ModifiedEntitiesViewProvider( applicationContext: ApplicationContext, - private val modifiedEntities: Collection + private val modifiedEntities: Collection, ) { val userAccountService: UserAccountService = applicationContext.getBean(UserAccountService::class.java) @@ -61,7 +61,7 @@ class ModifiedEntitiesViewProvider( exists = entityExistences[entity.entityClass to entity.entityId], modifications = entity.modifications, description = entity.describingData, - describingRelations = relations + describingRelations = relations, ) } } @@ -75,7 +75,7 @@ class ModifiedEntitiesViewProvider( exists = entityExistences[entity.entityClass to entity.entityId], modifications = entity.modifications, description = entity.describingData, - describingRelations = relations + describingRelations = relations, ) } } @@ -89,11 +89,11 @@ class ModifiedEntitiesViewProvider( it.value, describingEntities[entity.activityRevision.id] ?: let { _ -> Sentry.captureException( - IllegalStateException("No relation data for revision ${entity.activityRevision.id}") + IllegalStateException("No relation data for revision ${entity.activityRevision.id}"), ) return@mapNotNull null - } - ) + }, + ), ) } ?.toMap() @@ -134,20 +134,21 @@ class ModifiedEntitiesViewProvider( private fun extractCompressedRef( value: EntityDescriptionRef, - describingEntities: List + describingEntities: List, ): ExistenceEntityDescription { val entity = describingEntities.find { it.entityClass == value.entityClass && it.entityId == value.entityId } - val relations = entity?.describingRelations - ?.map { it.key to extractCompressedRef(it.value, describingEntities) } - ?.toMap() + val relations = + entity?.describingRelations + ?.map { it.key to extractCompressedRef(it.value, describingEntities) } + ?.toMap() return ExistenceEntityDescription( entityClass = value.entityClass, entityId = value.entityId, exists = entityExistences[value.entityClass to value.entityId], data = entity?.data ?: mapOf(), - relations = relations ?: mapOf() + relations = relations ?: mapOf(), ) } } diff --git a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/NotificationPreferencesBuilder.kt b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/NotificationPreferencesBuilder.kt index a1146d581d..d9281301aa 100644 --- a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/NotificationPreferencesBuilder.kt +++ b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/NotificationPreferencesBuilder.kt @@ -4,7 +4,7 @@ import io.tolgee.development.testDataBuilder.EntityDataBuilder import io.tolgee.model.notifications.NotificationPreferences class NotificationPreferencesBuilder( - val userAccountBuilder: UserAccountBuilder + val userAccountBuilder: UserAccountBuilder, ) : EntityDataBuilder { override var self: NotificationPreferences = NotificationPreferences(userAccountBuilder.self, null, emptyArray()) diff --git a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/UserAccountBuilder.kt b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/UserAccountBuilder.kt index 91997ccd5a..02c434d073 100644 --- a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/UserAccountBuilder.kt +++ b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/UserAccountBuilder.kt @@ -35,6 +35,5 @@ class UserAccountBuilder( fun addPat(ft: FT) = addOperation(data.pats, ft) - fun addNotificationPreferences(ft: FT) = - addOperation(data.notificationPreferences, ft) + fun addNotificationPreferences(ft: FT) = addOperation(data.notificationPreferences, ft) } diff --git a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationSubscriptionTestData.kt b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationSubscriptionTestData.kt index 88e057ea6b..5210ae8307 100644 --- a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationSubscriptionTestData.kt +++ b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationSubscriptionTestData.kt @@ -41,17 +41,19 @@ class NotificationSubscriptionTestData { role = UserAccount.Role.ADMIN } - val user1Builder = addUserAccountWithoutOrganization { - name = "User 1" - username = "user1" - user1 = this - } + val user1Builder = + addUserAccountWithoutOrganization { + name = "User 1" + username = "user1" + user1 = this + } - val user2Builder = addUserAccountWithoutOrganization { - name = "User 2" - username = "user2" - user2 = this - } + val user2Builder = + addUserAccountWithoutOrganization { + name = "User 2" + username = "user2" + user2 = this + } addOrganization { name = "Test org" diff --git a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationsTestData.kt b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationsTestData.kt index 8848ff0d57..833e5f2df2 100644 --- a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationsTestData.kt +++ b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationsTestData.kt @@ -139,11 +139,12 @@ class NotificationsTestData { val en = addEnglish() calmProjectFr = addFrench().self - val key = addKey { - name = "some-key" + val key = + addKey { + name = "some-key" - this@NotificationsTestData.keyCalmProject = this@addKey - } + this@NotificationsTestData.keyCalmProject = this@addKey + } addTranslation { this.key = key.self @@ -204,11 +205,12 @@ class NotificationsTestData { val cz = addCzech() val de = addGerman() - val key = addKey { - name = "some-key" + val key = + addKey { + name = "some-key" - this@NotificationsTestData.keyProject1 = this@addKey - } + this@NotificationsTestData.keyProject1 = this@addKey + } addTranslation { this.key = key.self @@ -303,11 +305,12 @@ class NotificationsTestData { project2 = this }.build { val en = addEnglish() - val key = addKey { - name = "some-key" + val key = + addKey { + name = "some-key" - this@NotificationsTestData.keyProject2 = this@addKey - } + this@NotificationsTestData.keyProject2 = this@addKey + } addTranslation { this.key = key.self diff --git a/backend/data/src/main/kotlin/io/tolgee/dtos/request/key/KeyScreenshotDto.kt b/backend/data/src/main/kotlin/io/tolgee/dtos/request/key/KeyScreenshotDto.kt index e55deb7375..878fdaed7b 100644 --- a/backend/data/src/main/kotlin/io/tolgee/dtos/request/key/KeyScreenshotDto.kt +++ b/backend/data/src/main/kotlin/io/tolgee/dtos/request/key/KeyScreenshotDto.kt @@ -5,7 +5,6 @@ import io.tolgee.dtos.request.KeyInScreenshotPositionDto data class KeyScreenshotDto( var text: String? = null, - @Schema(description = "Ids of screenshot uploaded with /v2/image-upload endpoint") var uploadedImageId: Long = 0, var positions: List? = null, diff --git a/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt b/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt index 411b7018b4..9da7fd19a8 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt @@ -5,7 +5,9 @@ import io.tolgee.dtos.cacheable.IPermission import io.tolgee.dtos.request.project.LanguagePermissions import io.tolgee.model.enums.ProjectPermissionType import io.tolgee.model.enums.Scope +import jakarta.persistence.CollectionTable import jakarta.persistence.Column +import jakarta.persistence.ElementCollection import jakarta.persistence.Entity import jakarta.persistence.EntityListeners import jakarta.persistence.EnumType @@ -79,7 +81,7 @@ class Permission( * Languages for TRANSLATIONS_EDIT scope. * When specified, user is restricted to edit specific language translations. */ - @ManyToMany(fetch = FetchType.EAGER) + @ManyToMany(fetch = FetchType.LAZY) @JoinTable(name = "permission_languages", inverseJoinColumns = [JoinColumn(name = "languages_id")]) var translateLanguages: MutableSet = mutableSetOf() @@ -87,14 +89,14 @@ class Permission( * Languages for TRANSLATIONS_EDIT scope. * When specified, user is restricted to edit specific language translations. */ - @ManyToMany(fetch = FetchType.EAGER) + @ManyToMany(fetch = FetchType.LAZY) var viewLanguages: MutableSet = mutableSetOf() /** * Languages for TRANSLATIONS_EDIT scope. * When specified, user is restricted to edit specific language translations. */ - @ManyToMany(fetch = FetchType.EAGER) + @ManyToMany(fetch = FetchType.LAZY) var stateChangeLanguages: MutableSet = mutableSetOf() constructor( @@ -132,14 +134,21 @@ class Permission( get() = this.project?.id override val organizationId: Long? get() = this.organization?.id - override val translateLanguageIds: Set? - get() = this.translateLanguages.map { it.id }.toSet() - override val viewLanguageIds: Set? - get() = this.viewLanguages.map { it.id }.toSet() + @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable(name = "permission_languages", joinColumns = [JoinColumn(name = "permission_id")]) + @Column(name = "languages_id") + override val translateLanguageIds: Set? = null - override val stateChangeLanguageIds: Set? - get() = this.stateChangeLanguages.map { it.id }.toSet() + @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable(name = "permission_view_languages", joinColumns = [JoinColumn(name = "permission_id")]) + @Column(name = "view_languages_id") + override val viewLanguageIds: Set? = null + + @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable(name = "permission_state_change_languages", joinColumns = [JoinColumn(name = "permission_id")]) + @Column(name = "state_change_languages_id") + override val stateChangeLanguageIds: Set? = null companion object { class PermissionListeners { diff --git a/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt b/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt index 5c7f36c1a4..09169eae1f 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt @@ -18,7 +18,6 @@ import jakarta.persistence.OrderBy import jakarta.validation.constraints.NotBlank import org.hibernate.annotations.ColumnDefault import org.hibernate.annotations.Type -import org.hibernate.annotations.TypeDef import org.hibernate.annotations.Where import java.util.* diff --git a/backend/data/src/main/kotlin/io/tolgee/model/notifications/NotificationPreferences.kt b/backend/data/src/main/kotlin/io/tolgee/model/notifications/NotificationPreferences.kt index 87054b17fa..4770be5717 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/notifications/NotificationPreferences.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/notifications/NotificationPreferences.kt @@ -16,35 +16,24 @@ package io.tolgee.model.notifications -import com.vladmihalcea.hibernate.type.array.EnumArrayType +import io.hypersistence.utils.hibernate.type.array.EnumArrayType import io.tolgee.model.Project import io.tolgee.model.UserAccount import io.tolgee.notifications.NotificationType +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.FetchType +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id +import jakarta.persistence.Index +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import jakarta.persistence.Table import org.hibernate.annotations.Parameter import org.hibernate.annotations.Type -import org.hibernate.annotations.TypeDef -import javax.persistence.Column -import javax.persistence.Entity -import javax.persistence.FetchType -import javax.persistence.GeneratedValue -import javax.persistence.GenerationType -import javax.persistence.Id -import javax.persistence.Index -import javax.persistence.JoinColumn -import javax.persistence.ManyToOne -import javax.persistence.Table @Entity -@TypeDef( - name = "enum-array", - typeClass = EnumArrayType::class, - parameters = [ - Parameter( - name = EnumArrayType.SQL_ARRAY_TYPE, - value = "varchar" - ) - ] -) @Table( indexes = [ Index( @@ -54,24 +43,22 @@ import javax.persistence.Table ), Index( name = "notification_preferences_user", - columnList = "user_account_id" + columnList = "user_account_id", ), Index( name = "notification_preferences_project", columnList = "project_id", - ) - ] + ), + ], ) class NotificationPreferences( @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(nullable = false) val userAccount: UserAccount, - @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(nullable = true) var project: Project?, - - @Type(type = "enum-array") + @Type(EnumArrayType::class, parameters = [Parameter(name = EnumArrayType.SQL_ARRAY_TYPE, value = "varchar")]) @Column(nullable = false, columnDefinition = "varchar[]") var disabledNotifications: Array, ) { diff --git a/backend/data/src/main/kotlin/io/tolgee/model/notifications/UserNotification.kt b/backend/data/src/main/kotlin/io/tolgee/model/notifications/UserNotification.kt index c81ddf93d9..7e531c5c7a 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/notifications/UserNotification.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/notifications/UserNotification.kt @@ -21,50 +21,46 @@ import io.tolgee.model.UserAccount import io.tolgee.model.activity.ActivityModifiedEntity import io.tolgee.model.batch.BatchJob import io.tolgee.notifications.NotificationType +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.EnumType +import jakarta.persistence.Enumerated +import jakarta.persistence.FetchType +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id +import jakarta.persistence.JoinColumn +import jakarta.persistence.JoinTable +import jakarta.persistence.ManyToMany +import jakarta.persistence.ManyToOne +import jakarta.persistence.OrderBy +import jakarta.persistence.SequenceGenerator +import jakarta.persistence.Temporal +import jakarta.persistence.TemporalType import org.hibernate.annotations.ColumnDefault import org.hibernate.annotations.UpdateTimestamp import java.util.* -import javax.persistence.Column -import javax.persistence.Entity -import javax.persistence.EnumType -import javax.persistence.Enumerated -import javax.persistence.FetchType -import javax.persistence.GeneratedValue -import javax.persistence.GenerationType -import javax.persistence.Id -import javax.persistence.JoinColumn -import javax.persistence.JoinTable -import javax.persistence.ManyToMany -import javax.persistence.ManyToOne -import javax.persistence.OrderBy -import javax.persistence.SequenceGenerator -import javax.persistence.Temporal -import javax.persistence.TemporalType @Entity class UserNotification( @Column(nullable = false) @Enumerated(EnumType.STRING) val type: NotificationType, - // This data is very likely to be useless when consuming the entity: lazy @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(nullable = false) val recipient: UserAccount, - // We most definitely need this to show the notification: eager @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(nullable = true) val project: Project?, - // We most definitely need this to show the notification: eager @ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "user_notification_modified_entities") val modifiedEntities: MutableList = mutableListOf(), - // We most definitely need this to show the notification: eager @ManyToOne(fetch = FetchType.EAGER) - val batchJob: BatchJob? = null + val batchJob: BatchJob? = null, ) { @Id @SequenceGenerator(name = "notification_seq", sequenceName = "sequence_notifications") diff --git a/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionsNotificationPreferencesDataView.kt b/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionsNotificationPreferencesDataView.kt index d326fd5366..1edae70b07 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionsNotificationPreferencesDataView.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionsNotificationPreferencesDataView.kt @@ -16,32 +16,66 @@ package io.tolgee.model.views +import io.tolgee.model.OrganizationRole +import io.tolgee.model.Permission +import io.tolgee.model.Project import io.tolgee.model.enums.OrganizationRoleType import io.tolgee.model.enums.ProjectPermissionType import io.tolgee.model.enums.Scope import io.tolgee.model.notifications.NotificationPreferences +import jakarta.persistence.Id +import jakarta.persistence.OneToMany -class UserAccountProjectPermissionsNotificationPreferencesDataView( - val id: Long, - val projectId: Long, - val organizationRole: OrganizationRoleType?, - val basePermissionsBasic: ProjectPermissionType?, - basePermissionsGranular: Array>?, - val permissionsBasic: ProjectPermissionType?, - permissionsGranular: Array>?, - permittedViewLanguages: String?, - globalNotificationPreferences: NotificationPreferences?, - projectNotificationPreferences: NotificationPreferences? +data class UserProjectMetadata( + @Id + val id: Long, + + @Id + val projectId: Long, + + @OneToMany + val organizationRole: OrganizationRole?, + + @OneToMany + val basePermissions: Permission?, + + @OneToMany + val permissions: Permission?, + + @OneToMany + val globalNotificationPreferences: NotificationPreferences?, + + @OneToMany + val projectNotificationPreferences: NotificationPreferences?, ) { - // My love for Hibernate have no limit 🥰🥰🥰 - val basePermissionsGranular = basePermissionsGranular?.map { enumValueOf(it.name) } - val permissionsGranular = permissionsGranular?.map { enumValueOf(it.name) } - val permittedViewLanguages = permittedViewLanguages?.let { - it.split(',') - .filter { part -> part.isNotEmpty() } - .map { part -> part.toLong() } - .ifEmpty { null } - } - - val notificationPreferences = projectNotificationPreferences ?: globalNotificationPreferences + val notificationPreferences + get() = projectNotificationPreferences ?: globalNotificationPreferences +} + +class UserAccountProjectPermissionsNotificationPreferencesDataView(data: Map) { + init { + println(data["permittedViewLanguages"]) + } + + val id = data["id"] as? Long ?: throw IllegalArgumentException() + + val projectId = data["projectId"] as? Long ?: throw IllegalArgumentException() + + val organizationRole = data["organizationRole"] as? OrganizationRoleType + + val basePermissionsBasic = data["basePermissionsBasic"] as? ProjectPermissionType + + val basePermissionsGranular = (data["basePermissionsGranular"] as? Array<*>) + ?.map { enumValueOf((it as? Enum<*>)?.name ?: throw IllegalArgumentException()) } + + val permissionsBasic = data["permissionsBasic"] as? ProjectPermissionType + + val permissionsGranular = (data["permissionsGranular"] as? Array<*>) + ?.map { enumValueOf((it as? Enum<*>)?.name ?: throw IllegalArgumentException()) } + + val permittedViewLanguages = (data["permittedViewLanguages"] as? Array<*>) + ?.map { (it as? String)?.toLong() ?: throw IllegalArgumentException() } + + val notificationPreferences = (data["projectNotificationPreferences"] ?: data["globalNotificationPreferences"]) + as? NotificationPreferences } diff --git a/backend/data/src/main/kotlin/io/tolgee/model/views/UserProjectMetadataView.kt b/backend/data/src/main/kotlin/io/tolgee/model/views/UserProjectMetadataView.kt new file mode 100644 index 0000000000..d859caff92 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/model/views/UserProjectMetadataView.kt @@ -0,0 +1,40 @@ +/** + * Copyright (C) 2023 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.model.views + +import io.tolgee.model.Permission +import io.tolgee.model.enums.OrganizationRoleType +import io.tolgee.model.notifications.NotificationPreferences + +data class UserProjectMetadataView( + val userAccountId: Long, + + val projectId: Long, + + val organizationRole: OrganizationRoleType?, + + val basePermissions: Permission?, + + val permissions: Permission?, + + val globalNotificationPreferences: NotificationPreferences?, + + val projectNotificationPreferences: NotificationPreferences?, +) { + val notificationPreferences + get() = projectNotificationPreferences ?: globalNotificationPreferences +} diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt index cdf2db5d57..43945348d7 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt @@ -23,8 +23,8 @@ import io.tolgee.model.notifications.NotificationPreferences import io.tolgee.notifications.dto.NotificationPreferencesDto import io.tolgee.repository.notifications.NotificationPreferencesRepository import io.tolgee.service.security.SecurityService +import jakarta.persistence.EntityManager import org.springframework.stereotype.Service -import javax.persistence.EntityManager @Service class NotificationPreferencesService( @@ -42,31 +42,42 @@ class NotificationPreferencesService( } fun getGlobalPreferences(user: Long): NotificationPreferencesDto { - val entity = notificationPreferencesRepository.findByUserAccountIdAndProjectId(user, null) - ?: return NotificationPreferencesDto.createBlank() + val entity = + notificationPreferencesRepository.findByUserAccountIdAndProjectId(user, null) + ?: return NotificationPreferencesDto.createBlank() return NotificationPreferencesDto.fromEntity(entity) } - fun getProjectPreferences(user: Long, project: Long): NotificationPreferencesDto { + fun getProjectPreferences( + user: Long, + project: Long, + ): NotificationPreferencesDto { // If the user cannot see the project, the project "does not exist". val scopes = securityService.getProjectPermissionScopes(project, user) ?: emptyArray() if (scopes.isEmpty()) throw NotFoundException() - val entity = notificationPreferencesRepository.findByUserAccountIdAndProjectId(user, null) - ?: throw NotFoundException() + val entity = + notificationPreferencesRepository.findByUserAccountIdAndProjectId(user, null) + ?: throw NotFoundException() return NotificationPreferencesDto.fromEntity(entity) } - fun setPreferencesOfUser(user: Long, dto: NotificationPreferencesDto): NotificationPreferences { + fun setPreferencesOfUser( + user: Long, + dto: NotificationPreferencesDto, + ): NotificationPreferences { return setPreferencesOfUser( entityManager.getReference(UserAccount::class.java, user), dto, ) } - fun setPreferencesOfUser(user: UserAccount, dto: NotificationPreferencesDto): NotificationPreferences { + fun setPreferencesOfUser( + user: UserAccount, + dto: NotificationPreferencesDto, + ): NotificationPreferences { return doSetPreferencesOfUser(user, null, dto) } @@ -106,11 +117,14 @@ class NotificationPreferencesService( user, project, dto.disabledNotifications.toTypedArray(), - ) + ), ) } - fun deleteProjectPreferencesOfUser(user: Long, project: Long) { + fun deleteProjectPreferencesOfUser( + user: Long, + project: Long, + ) { notificationPreferencesRepository.deleteByUserAccountIdAndProjectId(user, project) } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationStatus.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationStatus.kt index 157c985e65..d80da10164 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationStatus.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationStatus.kt @@ -17,5 +17,7 @@ package io.tolgee.notifications enum class NotificationStatus { - UNREAD, READ, DONE + UNREAD, + READ, + DONE, } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationType.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationType.kt index 1b13671bce..cf66b8fffc 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationType.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationType.kt @@ -35,22 +35,24 @@ enum class NotificationType { ; companion object { - val ACTIVITY_NOTIFICATIONS: EnumSet = EnumSet.of( - ACTIVITY_LANGUAGES_CREATED, - ACTIVITY_KEYS_CREATED, - ACTIVITY_KEYS_UPDATED, - ACTIVITY_KEYS_SCREENSHOTS_UPLOADED, - ACTIVITY_SOURCE_STRINGS_UPDATED, - ACTIVITY_TRANSLATIONS_UPDATED, - ACTIVITY_TRANSLATION_OUTDATED, - ACTIVITY_TRANSLATION_REVIEWED, - ACTIVITY_TRANSLATION_UNREVIEWED, - ACTIVITY_NEW_COMMENTS, - ACTIVITY_COMMENTS_MENTION, - ) + val ACTIVITY_NOTIFICATIONS: EnumSet = + EnumSet.of( + ACTIVITY_LANGUAGES_CREATED, + ACTIVITY_KEYS_CREATED, + ACTIVITY_KEYS_UPDATED, + ACTIVITY_KEYS_SCREENSHOTS_UPLOADED, + ACTIVITY_SOURCE_STRINGS_UPDATED, + ACTIVITY_TRANSLATIONS_UPDATED, + ACTIVITY_TRANSLATION_OUTDATED, + ACTIVITY_TRANSLATION_REVIEWED, + ACTIVITY_TRANSLATION_UNREVIEWED, + ACTIVITY_NEW_COMMENTS, + ACTIVITY_COMMENTS_MENTION, + ) - val BATCH_JOB_NOTIFICATIONS: EnumSet = EnumSet.of( - BATCH_JOB_ERRORED, - ) + val BATCH_JOB_NOTIFICATIONS: EnumSet = + EnumSet.of( + BATCH_JOB_ERRORED, + ) } } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationDebouncer.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationDebouncer.kt index 5bf60d2087..b3e7fa399c 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationDebouncer.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationDebouncer.kt @@ -16,7 +16,6 @@ package io.tolgee.notifications -import io.tolgee.model.Project import io.tolgee.model.UserAccount import io.tolgee.model.activity.ActivityModifiedEntity import io.tolgee.model.notifications.UserNotification @@ -35,7 +34,7 @@ typealias UserNotificationDebounceResult = Pair, List + params: List, ): UserNotificationDebounceResult { if (NotificationType.ACTIVITY_NOTIFICATIONS.contains(notificationDto.type)) { return debounceActivityNotification(notificationDto, params) @@ -81,74 +80,79 @@ class UserNotificationDebouncer( notificationDto: NotificationCreateDto, recipients: List, ): Map { - val notifications = when { - translationUpdateNotificationTypes.contains(notificationDto.type) -> - findCandidatesForTranslationUpdateNotificationDebouncing( - notificationDto.type, - notificationDto.project, - recipients, - notificationDto.modifiedEntities, - ) - - commentNotificationTypes.contains(notificationDto.type) -> - findCandidatesForCommentNotificationDebouncing( - notificationDto.project, - recipients, - notificationDto.modifiedEntities, - ) - - else -> - userNotificationRepository.findCandidatesForNotificationDebouncing( - notificationDto.type, - notificationDto.project, - recipients, - ) - } + val notifications = + when { + translationUpdateNotificationTypes.contains(notificationDto.type) -> + findCandidatesForTranslationUpdateNotificationDebouncing( + notificationDto.type, + notificationDto.projectId, + recipients, + notificationDto.modifiedEntities, + ) + + commentNotificationTypes.contains(notificationDto.type) -> + findCandidatesForCommentNotificationDebouncing( + notificationDto.projectId, + recipients, + notificationDto.modifiedEntities, + ) + + else -> + userNotificationRepository.findCandidatesForNotificationDebouncing( + notificationDto.type, + notificationDto.projectId, + recipients, + ) + } return notifications.associateBy { it.recipient.id } } private fun findCandidatesForTranslationUpdateNotificationDebouncing( type: NotificationType, - project: Project, + projectId: Long, recipients: List, entities: List?, ): List { - val keyId = entities?.find { it.entityClass == Translation::class.simpleName } - ?.describingRelations?.get("key")?.entityId ?: 0L + val keyId = + entities?.find { it.entityClass == Translation::class.simpleName } + ?.describingRelations?.get("key")?.entityId ?: 0L return userNotificationRepository.findCandidatesForTranslationUpdateNotificationDebouncing( type, - project, + projectId, recipients, keyId, ) } private fun findCandidatesForCommentNotificationDebouncing( - project: Project, + projectId: Long, recipients: List, entities: List?, ): List { - val translationId = entities?.find { it.entityClass == TranslationComment::class.simpleName } - ?.describingRelations?.get("translation")?.entityId ?: 0L + val translationId = + entities?.find { it.entityClass == TranslationComment::class.simpleName } + ?.describingRelations?.get("translation")?.entityId ?: 0L return userNotificationRepository.findCandidatesForCommentNotificationDebouncing( - project, + projectId, recipients, translationId, ) } companion object { - val translationUpdateNotificationTypes: EnumSet = EnumSet.of( - NotificationType.ACTIVITY_SOURCE_STRINGS_UPDATED, - NotificationType.ACTIVITY_TRANSLATIONS_UPDATED, - ) - - val commentNotificationTypes: EnumSet = EnumSet.of( - NotificationType.ACTIVITY_NEW_COMMENTS, - NotificationType.ACTIVITY_COMMENTS_MENTION, - ) + val translationUpdateNotificationTypes: EnumSet = + EnumSet.of( + NotificationType.ACTIVITY_SOURCE_STRINGS_UPDATED, + NotificationType.ACTIVITY_TRANSLATIONS_UPDATED, + ) + + val commentNotificationTypes: EnumSet = + EnumSet.of( + NotificationType.ACTIVITY_NEW_COMMENTS, + NotificationType.ACTIVITY_COMMENTS_MENTION, + ) } } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt index 5487c1e516..0621d59646 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt @@ -21,6 +21,7 @@ import io.tolgee.notifications.dto.NotificationCreateDto import io.tolgee.notifications.dto.UserNotificationParamsDto import io.tolgee.notifications.events.UserNotificationPushEvent import io.tolgee.repository.notifications.UserNotificationRepository +import jakarta.persistence.EntityManager import org.springframework.context.ApplicationEventPublisher import org.springframework.data.domain.Pageable import org.springframework.stereotype.Service @@ -28,29 +29,36 @@ import org.springframework.transaction.annotation.Transactional @Service class UserNotificationService( + private val entityManager: EntityManager, private val userNotificationRepository: UserNotificationRepository, private val applicationEventPublisher: ApplicationEventPublisher, private val userNotificationDebouncer: UserNotificationDebouncer, ) { @Transactional - fun dispatchNotification(notificationDto: NotificationCreateDto, params: UserNotificationParamsDto) { + fun dispatchNotification( + notificationDto: NotificationCreateDto, + params: UserNotificationParamsDto, + ) { return dispatchNotifications(notificationDto, listOf(params)) } @Transactional - fun dispatchNotifications(notificationDto: NotificationCreateDto, params: List) { + fun dispatchNotifications( + notificationDto: NotificationCreateDto, + params: List, + ) { val createdUserNotificationObjects = mutableSetOf() val updatedUserNotificationObjects = mutableSetOf() val (processed, remaining) = userNotificationDebouncer.debounce(notificationDto, params) updatedUserNotificationObjects.addAll( - userNotificationRepository.saveAll(processed) + userNotificationRepository.saveAll(processed), ) remaining.forEach { - val notification = notificationDto.toUserNotificationEntity(it) + val notification = notificationDto.toUserNotificationEntity(it, entityManager) createdUserNotificationObjects.add( - userNotificationRepository.save(notification) + userNotificationRepository.save(notification), ) } @@ -59,7 +67,7 @@ class UserNotificationService( UserNotificationPushEvent( createdUserNotificationObjects, updatedUserNotificationObjects, - ) + ), ) } @@ -80,7 +88,10 @@ class UserNotificationService( } @Transactional - fun markAsRead(user: Long, notifications: Collection) { + fun markAsRead( + user: Long, + notifications: Collection, + ) { return userNotificationRepository.markAsRead(user, notifications) } @@ -90,12 +101,18 @@ class UserNotificationService( } @Transactional - fun markAsUnread(user: Long, notifications: Collection) { + fun markAsUnread( + user: Long, + notifications: Collection, + ) { return userNotificationRepository.markAsUnread(user, notifications) } @Transactional - fun markAsDone(user: Long, notifications: Collection) { + fun markAsDone( + user: Long, + notifications: Collection, + ) { return userNotificationRepository.markAsDone(user, notifications) } @@ -105,7 +122,10 @@ class UserNotificationService( } @Transactional - fun unmarkAsDone(user: Long, notifications: Collection) { + fun unmarkAsDone( + user: Long, + notifications: Collection, + ) { return userNotificationRepository.unmarkAsDone(user, notifications) } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt index 8ddd86a117..855938f17d 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt @@ -16,12 +16,14 @@ package io.tolgee.notifications.dispatchers +import io.tolgee.dtos.ComputedPermissionDto +import io.tolgee.model.Permission import io.tolgee.model.Screenshot import io.tolgee.model.UserAccount import io.tolgee.model.activity.ActivityModifiedEntity import io.tolgee.model.enums.Scope import io.tolgee.model.translation.Translation -import io.tolgee.model.views.UserAccountProjectPermissionsNotificationPreferencesDataView +import io.tolgee.model.views.UserProjectMetadataView import io.tolgee.notifications.NotificationType import io.tolgee.notifications.UserNotificationService import io.tolgee.notifications.dto.UserNotificationParamsDto @@ -31,12 +33,14 @@ import io.tolgee.service.security.PermissionService import io.tolgee.service.security.UserAccountService import io.tolgee.util.Logging import io.tolgee.util.logger +import jakarta.persistence.EntityManager import org.springframework.context.event.EventListener import org.springframework.scheduling.annotation.Async +import org.springframework.scheduling.annotation.EnableAsync import org.springframework.stereotype.Component -import javax.persistence.EntityManager @Component +@EnableAsync(proxyTargetClass = true) class UserNotificationDispatch( private val userAccountService: UserAccountService, private val permissionService: PermissionService, @@ -60,20 +64,23 @@ class UserNotificationDispatch( } private fun handleActivityNotification(e: NotificationCreateEvent) { - val users = userAccountService.getAllPermissionInformationOfPermittedUsersInProject(e.notification.project.id) - .filter { - it.notificationPreferences?.disabledNotifications?.contains(e.notification.type) != true && - it.id != e.responsibleUser?.id - } + val users = + userAccountService.getAllConnectedUserProjectMetadataViews(e.notification.projectId) + .filter { + it.notificationPreferences?.disabledNotifications?.contains(e.notification.type) != true && + it.userAccountId != e.responsibleUserId + } - val translationToLanguageMap = e.notification.modifiedEntities!! - .filter { it.entityClass == Translation::class.simpleName } - .map { it.entityId } - .let { if (it.isEmpty()) emptyMap() else languageService.findLanguageIdsOfTranslations(it) } + val translationToLanguageMap = + e.notification.modifiedEntities!! + .filter { it.entityClass == Translation::class.simpleName } + .map { it.entityId } + .let { if (it.isEmpty()) emptyMap() else languageService.findLanguageIdsOfTranslations(it) } - val notifications = users.mapNotNull { - handleActivityNotificationForUser(e, translationToLanguageMap, it) - } + val notifications = + users.mapNotNull { + handleActivityNotificationForUser(e, translationToLanguageMap, it) + } userNotificationService.dispatchNotifications(e.notification, notifications) } @@ -86,37 +93,40 @@ class UserNotificationDispatch( val author = batchJob.author ?: return userNotificationService.dispatchNotification( e.notification, - UserNotificationParamsDto(author) + UserNotificationParamsDto(author), ) } private fun handleActivityNotificationForUser( - e: NotificationCreateEvent, - translationToLanguageMap: Map, - userPermissionData: UserAccountProjectPermissionsNotificationPreferencesDataView, + e: NotificationCreateEvent, + translationToLanguageMap: Map, + userProjectMetadataView: UserProjectMetadataView, ): UserNotificationParamsDto? { - val permissions = permissionService.computeProjectPermission(userPermissionData).expandedScopes + val permissions = permissionService.computeProjectPermission( + userProjectMetadataView.organizationRole, + userProjectMetadataView.basePermissions, + userProjectMetadataView.permissions, + ) // Filter the entities the user is allowed to see - val filteredModifiedEntities = filterModifiedEntities( - e.notification.modifiedEntities!!, - permissions, - userPermissionData.permittedViewLanguages, - translationToLanguageMap, - ) + val filteredModifiedEntities = + filterModifiedEntities( + e.notification.modifiedEntities!!, + permissions, + translationToLanguageMap, + ) if (filteredModifiedEntities.isEmpty()) return null return UserNotificationParamsDto( - recipient = entityManager.getReference(UserAccount::class.java, userPermissionData.id), + recipient = entityManager.getReference(UserAccount::class.java, userProjectMetadataView.userAccountId), modifiedEntities = filteredModifiedEntities.toSet(), ) } private fun filterModifiedEntities( modifiedEntities: List, - permissions: Array, - permittedViewLanguages: List?, + permissions: ComputedPermissionDto, translationToLanguageMap: Map, ): Set { return modifiedEntities @@ -125,25 +135,24 @@ class UserNotificationDispatch( Screenshot::class.simpleName -> isUserAllowedToSeeScreenshot(permissions) Translation::class.simpleName -> - isUserAllowedToSeeTranslation(it, permissions, permittedViewLanguages, translationToLanguageMap) + isUserAllowedToSeeTranslation(it, permissions, translationToLanguageMap) else -> true } }.toSet() } - private fun isUserAllowedToSeeScreenshot(permissions: Array): Boolean { - return permissions.contains(Scope.SCREENSHOTS_VIEW) + private fun isUserAllowedToSeeScreenshot(permissions: ComputedPermissionDto): Boolean { + return permissions.expandedScopes.contains(Scope.SCREENSHOTS_VIEW) } private fun isUserAllowedToSeeTranslation( entity: ActivityModifiedEntity, - permissions: Array, - permittedViewLanguages: List?, + permissions: ComputedPermissionDto, translationToLanguageMap: Map, ): Boolean { - if (!permissions.contains(Scope.TRANSLATIONS_VIEW)) return false + if (!permissions.expandedScopes.contains(Scope.TRANSLATIONS_VIEW)) return false val language = translationToLanguageMap[entity.entityId] ?: return false - return permittedViewLanguages?.contains(language) != false + return permissions.viewLanguageIds.isNullOrEmpty() || permissions.viewLanguageIds.contains(language) } } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt index 0ac6a6e4db..b69d6a0e5e 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt @@ -21,23 +21,27 @@ import io.tolgee.model.activity.ActivityModifiedEntity import io.tolgee.model.batch.BatchJob import io.tolgee.model.notifications.UserNotification import io.tolgee.notifications.NotificationType +import jakarta.persistence.EntityManager data class NotificationCreateDto( val type: NotificationType, - val project: Project, + val projectId: Long, val modifiedEntities: MutableList? = null, - val batchJob: BatchJob? = null + val batchJob: BatchJob? = null, ) { - fun toUserNotificationEntity(params: UserNotificationParamsDto): UserNotification { + fun toUserNotificationEntity(params: UserNotificationParamsDto, em: EntityManager): UserNotification { return UserNotification( type = type, recipient = params.recipient, - project = project, - modifiedEntities = params.modifiedEntities.toMutableList() + project = em.getReference(Project::class.java, projectId), + modifiedEntities = params.modifiedEntities.toMutableList(), ) } - fun mergeIntoUserNotificationEntity(userNotification: UserNotification, params: UserNotificationParamsDto) { + fun mergeIntoUserNotificationEntity( + userNotification: UserNotification, + params: UserNotificationParamsDto, + ) { when { NotificationType.ACTIVITY_NOTIFICATIONS.contains(userNotification.type) -> mergeIntoNotificationEntityActivity(userNotification, params) diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationPreferencesDto.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationPreferencesDto.kt index 7698de36ad..6b1051d5c6 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationPreferencesDto.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationPreferencesDto.kt @@ -22,7 +22,7 @@ import io.tolgee.notifications.NotificationType data class NotificationPreferencesDto( @Schema(description = "List of notification types the user does not want to receive.") - val disabledNotifications: List + val disabledNotifications: List, ) { companion object { fun fromEntity(notificationPreferences: NotificationPreferences): NotificationPreferencesDto { diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/UserNotificationParamsDto.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/UserNotificationParamsDto.kt index e97299f3db..5637526046 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/UserNotificationParamsDto.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/UserNotificationParamsDto.kt @@ -21,5 +21,5 @@ import io.tolgee.model.activity.ActivityModifiedEntity data class UserNotificationParamsDto( val recipient: UserAccount, - val modifiedEntities: Set = emptySet() + val modifiedEntities: Set = emptySet(), ) diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationCreateEvent.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationCreateEvent.kt index 4550ada6fc..b1a6fa9263 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationCreateEvent.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationCreateEvent.kt @@ -19,8 +19,8 @@ package io.tolgee.notifications.events import io.tolgee.model.UserAccount import io.tolgee.notifications.dto.NotificationCreateDto -class NotificationCreateEvent( +data class NotificationCreateEvent( val notification: NotificationCreateDto, - val responsibleUser: UserAccount?, - val source: Any? = null + val responsibleUserId: Long?, + val source: Any? = null, ) diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt index a78fc1f5f5..75bdfa29e9 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt @@ -33,18 +33,17 @@ import io.tolgee.notifications.events.NotificationCreateEvent import io.tolgee.service.LanguageService import io.tolgee.util.Logging import io.tolgee.util.logger +import jakarta.persistence.EntityManager import org.springframework.context.ApplicationEventPublisher import org.springframework.context.event.EventListener import org.springframework.stereotype.Component import org.springframework.transaction.annotation.Transactional -import javax.persistence.EntityManager private typealias SortedTranslations = List>> @Component class ActivityEventListener( private val applicationEventPublisher: ApplicationEventPublisher, - private val entityManager: EntityManager, private val languageService: LanguageService, ) : Logging { @EventListener @@ -56,39 +55,37 @@ class ActivityEventListener( "Received project activity event - {} on proj#{} ({} entities modified)", e.activityRevision.type, e.activityRevision.projectId, - e.activityRevision.modifiedEntities.size + e.activityRevision.modifiedEntities.size, ) val projectId = e.activityRevision.projectId ?: return - val project = entityManager.getReference(Project::class.java, projectId) - val responsibleUser = e.activityRevision.authorId?.let { - entityManager.getReference(UserAccount::class.java, it) - } + val responsibleUserId = e.activityRevision.authorId when (e.activityRevision.type) { // ACTIVITY_LANGUAGES_CREATED ActivityType.CREATE_LANGUAGE -> - processSimpleActivity(NotificationType.ACTIVITY_LANGUAGES_CREATED, project, responsibleUser, e) + processSimpleActivity(NotificationType.ACTIVITY_LANGUAGES_CREATED, projectId, responsibleUserId, e) // ACTIVITY_KEYS_CREATED ActivityType.CREATE_KEY -> - processSimpleActivity(NotificationType.ACTIVITY_KEYS_CREATED, project, responsibleUser, e) + processSimpleActivity(NotificationType.ACTIVITY_KEYS_CREATED, projectId, responsibleUserId, e) // ACTIVITY_KEYS_UPDATED ActivityType.KEY_TAGS_EDIT, ActivityType.KEY_NAME_EDIT, ActivityType.BATCH_TAG_KEYS, ActivityType.BATCH_UNTAG_KEYS, - ActivityType.BATCH_SET_KEYS_NAMESPACE -> - processSimpleActivity(NotificationType.ACTIVITY_KEYS_UPDATED, project, responsibleUser, e) + ActivityType.BATCH_SET_KEYS_NAMESPACE, + -> + processSimpleActivity(NotificationType.ACTIVITY_KEYS_UPDATED, projectId, responsibleUserId, e) // ACTIVITY_KEYS_UPDATED, ACTIVITY_KEYS_SCREENSHOTS_UPLOADED, ACTIVITY_TRANSLATIONS_* ActivityType.COMPLEX_EDIT -> - processComplexEdit(project, responsibleUser, e) + processComplexEdit(projectId, responsibleUserId, e) // ACTIVITY_KEYS_SCREENSHOTS_UPLOADED ActivityType.SCREENSHOT_ADD -> - processScreenshotUpdate(project, responsibleUser, e) + processScreenshotUpdate(projectId, responsibleUserId, e) // ACTIVITY_TRANSLATIONS_* ActivityType.SET_TRANSLATIONS, @@ -98,19 +95,20 @@ class ActivityEventListener( ActivityType.AUTO_TRANSLATE, ActivityType.BATCH_CLEAR_TRANSLATIONS, ActivityType.BATCH_COPY_TRANSLATIONS, - ActivityType.BATCH_SET_TRANSLATION_STATE -> - processSetTranslations(project, responsibleUser, e) + ActivityType.BATCH_SET_TRANSLATION_STATE, + -> + processSetTranslations(projectId, responsibleUserId, e) ActivityType.SET_OUTDATED_FLAG -> - processOutdatedFlagUpdate(project, responsibleUser, e) + processOutdatedFlagUpdate(projectId, responsibleUserId, e) // ACTIVITY_NEW_COMMENTS (ACTIVITY_COMMENTS_MENTION is user-specific and not computed here) ActivityType.TRANSLATION_COMMENT_ADD -> - processSimpleActivity(NotificationType.ACTIVITY_NEW_COMMENTS, project, responsibleUser, e) + processSimpleActivity(NotificationType.ACTIVITY_NEW_COMMENTS, projectId, responsibleUserId, e) // ACTIVITY_KEYS_CREATED, ACTIVITY_TRANSLATIONS_* ActivityType.IMPORT -> - processImport(project, responsibleUser, e) + processImport(projectId, responsibleUserId, e) // We don't care about those, ignore them. // They're explicitly not written as a single `else` branch, @@ -129,7 +127,8 @@ class ActivityEventListener( ActivityType.EDIT_PROJECT, ActivityType.NAMESPACE_EDIT, ActivityType.AUTOMATION, - null -> {} + null, + -> {} } } @@ -138,16 +137,16 @@ class ActivityEventListener( */ private fun processSimpleActivity( type: NotificationType, - project: Project, - responsibleUser: UserAccount?, + projectId: Long, + responsibleUserId: Long?, e: OnProjectActivityStoredEvent, ) { applicationEventPublisher.publishEvent( NotificationCreateEvent( - NotificationCreateDto(type, project, e.activityRevision.modifiedEntities), - responsibleUser, + NotificationCreateDto(type, projectId, e.activityRevision.modifiedEntities), + responsibleUserId, source = e, - ) + ), ) } @@ -155,41 +154,42 @@ class ActivityEventListener( * Emits multiple notification create events depending on the details of the complex edition. */ private fun processComplexEdit( - project: Project, - responsibleUser: UserAccount?, + projectId: Long, + responsibleUserId: Long?, e: OnProjectActivityStoredEvent, ) { - processComplexEditKeyUpdate(project, responsibleUser, e) - processScreenshotUpdate(project, responsibleUser, e) - processSetTranslations(project, responsibleUser, e) + processComplexEditKeyUpdate(projectId, responsibleUserId, e) + processScreenshotUpdate(projectId, responsibleUserId, e) + processSetTranslations(projectId, responsibleUserId, e) } private fun processComplexEditKeyUpdate( - project: Project, - responsibleUser: UserAccount?, + projectId: Long, + responsibleUserId: Long?, e: OnProjectActivityStoredEvent, ) { // The key was updated if: // The entity is a Key and its name or namespace was modified; // The entity is a KeyMeta and its tags were modified. - val relevantEntities = e.activityRevision.modifiedEntities.filter { - ( - it.entityClass == Key::class.simpleName && - (it.modifications.containsKey("name") || it.modifications.containsKey("namespace")) - ) || + val relevantEntities = + e.activityRevision.modifiedEntities.filter { ( - it.entityClass == KeyMeta::class.simpleName && - it.modifications.containsKey("tags") + it.entityClass == Key::class.simpleName && + (it.modifications.containsKey("name") || it.modifications.containsKey("namespace")) + ) || + ( + it.entityClass == KeyMeta::class.simpleName && + it.modifications.containsKey("tags") ) - } + } if (relevantEntities.isNotEmpty()) { applicationEventPublisher.publishEvent( NotificationCreateEvent( - NotificationCreateDto(NotificationType.ACTIVITY_KEYS_UPDATED, project, relevantEntities.toMutableList()), - responsibleUser, + NotificationCreateDto(NotificationType.ACTIVITY_KEYS_UPDATED, projectId, relevantEntities.toMutableList()), + responsibleUserId, source = e, - ) + ), ) } } @@ -200,31 +200,35 @@ class ActivityEventListener( * Refer to the Hacking Documentation, Notifications, Activity Notifications - User Dispatch, §2.2.2. */ private fun processSetTranslations( - project: Project, - responsibleUser: UserAccount?, + projectId: Long, + responsibleUserId: Long?, e: OnProjectActivityStoredEvent, - modifiedEntities: List = e.activityRevision.modifiedEntities + modifiedEntities: List = e.activityRevision.modifiedEntities, ) { - val baseLanguageId = languageService.getBaseLanguageForProject(project) - val sortedTranslations = sortTranslations( - modifiedEntities, - baseLanguage = baseLanguageId ?: 0L - ) + val baseLanguageId = languageService.getBaseLanguageForProjectId(projectId) + val sortedTranslations = + sortTranslations( + modifiedEntities, + baseLanguage = baseLanguageId ?: 0L, + ) for ((type, translations) in sortedTranslations) { if (translations.isNotEmpty()) { applicationEventPublisher.publishEvent( NotificationCreateEvent( - NotificationCreateDto(type, project, translations), - responsibleUser, + NotificationCreateDto(type, projectId, translations), + responsibleUserId, source = e, - ) + ), ) } } } - private fun sortTranslations(entities: List, baseLanguage: Long): SortedTranslations { + private fun sortTranslations( + entities: List, + baseLanguage: Long, + ): SortedTranslations { val updatedSourceTranslations = mutableListOf() val updatedTranslations = mutableListOf() val reviewedTranslations = mutableListOf() @@ -238,16 +242,19 @@ class ActivityEventListener( if (text != null) { val languageId = it.describingRelations?.get("language")?.entityId - if (languageId == baseLanguage) + if (languageId == baseLanguage) { updatedSourceTranslations.add(it) - else + } else { updatedTranslations.add(it) + } } - if (state?.new == TranslationState.REVIEWED.name) + if (state?.new == TranslationState.REVIEWED.name) { reviewedTranslations.add(it) - if (state?.new == TranslationState.TRANSLATED.name && state.old == TranslationState.REVIEWED.name) + } + if (state?.new == TranslationState.TRANSLATED.name && state.old == TranslationState.REVIEWED.name) { unreviewedTranslations.add(it) + } } return listOf( @@ -259,80 +266,84 @@ class ActivityEventListener( } private fun processOutdatedFlagUpdate( - project: Project, - responsibleUser: UserAccount?, + projectId: Long, + responsibleUserId: Long?, e: OnProjectActivityStoredEvent, ) { - val outdatedTranslations = e.activityRevision.modifiedEntities - .filter { it.modifications["outdated"]?.new == true } + val outdatedTranslations = + e.activityRevision.modifiedEntities + .filter { it.modifications["outdated"]?.new == true } if (outdatedTranslations.isNotEmpty()) { applicationEventPublisher.publishEvent( NotificationCreateEvent( NotificationCreateDto( type = NotificationType.ACTIVITY_TRANSLATION_OUTDATED, - project = project, - modifiedEntities = outdatedTranslations.toMutableList() + projectId = projectId, + modifiedEntities = outdatedTranslations.toMutableList(), ), - responsibleUser, + responsibleUserId, source = e, - ) + ), ) } } private fun processScreenshotUpdate( - project: Project, - responsibleUser: UserAccount?, + projectId: Long, + responsibleUserId: Long?, e: OnProjectActivityStoredEvent, ) { - val addedScreenshots = e.activityRevision.modifiedEntities - .filter { it.entityClass == Screenshot::class.simpleName && it.revisionType == RevisionType.ADD } + val addedScreenshots = + e.activityRevision.modifiedEntities + .filter { it.entityClass == Screenshot::class.simpleName && it.revisionType == RevisionType.ADD } if (addedScreenshots.isNotEmpty()) { applicationEventPublisher.publishEvent( NotificationCreateEvent( NotificationCreateDto( type = NotificationType.ACTIVITY_KEYS_SCREENSHOTS_UPLOADED, - project = project, - modifiedEntities = addedScreenshots.toMutableList() + projectId = projectId, + modifiedEntities = addedScreenshots.toMutableList(), ), - responsibleUser, + responsibleUserId, source = e, - ) + ), ) } } private fun processImport( - project: Project, - responsibleUser: UserAccount?, + projectId: Long, + responsibleUserId: Long?, e: OnProjectActivityStoredEvent, ) { - val createdKeys = e.activityRevision.modifiedEntities - .filter { it.entityClass == Key::class.simpleName && it.revisionType == RevisionType.ADD } - .toMutableList() + val createdKeys = + e.activityRevision.modifiedEntities + .filter { it.entityClass == Key::class.simpleName && it.revisionType == RevisionType.ADD } + .toMutableList() val keyIds = createdKeys.map { it.entityId }.toSet() - val updatedTranslations = e.activityRevision.modifiedEntities - .filter { - val isFromNewKey = keyIds.contains(it.describingRelations?.get("key")?.entityId ?: 0L) - if (isFromNewKey) createdKeys.add(it) - !isFromNewKey - } + val updatedTranslations = + e.activityRevision.modifiedEntities + .filter { + val isFromNewKey = keyIds.contains(it.describingRelations?.get("key")?.entityId ?: 0L) + if (isFromNewKey) createdKeys.add(it) + !isFromNewKey + } if (createdKeys.isNotEmpty()) { applicationEventPublisher.publishEvent( NotificationCreateEvent( - NotificationCreateDto(NotificationType.ACTIVITY_KEYS_CREATED, project, createdKeys.toMutableList()), - responsibleUser, + NotificationCreateDto(NotificationType.ACTIVITY_KEYS_CREATED, projectId, createdKeys.toMutableList()), + responsibleUserId, source = e, - ) + ), ) } if (updatedTranslations.isNotEmpty()) { - processSetTranslations(project, responsibleUser, e, updatedTranslations) + processSetTranslations(projectId, responsibleUserId, e, updatedTranslations) } } } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt index b274e73376..7b596432c7 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt @@ -24,10 +24,10 @@ import io.tolgee.notifications.dto.NotificationCreateDto import io.tolgee.notifications.events.NotificationCreateEvent import io.tolgee.util.Logging import io.tolgee.util.logger +import jakarta.persistence.EntityManager import org.springframework.context.ApplicationEventPublisher import org.springframework.context.event.EventListener import org.springframework.stereotype.Component -import javax.persistence.EntityManager @Component class BatchJobListener( @@ -43,17 +43,16 @@ class BatchJobListener( ) val job = entityManager.getReference(BatchJob::class.java, e.job.id) - val project = entityManager.getReference(Project::class.java, e.job.projectId) applicationEventPublisher.publishEvent( NotificationCreateEvent( NotificationCreateDto( type = NotificationType.BATCH_JOB_ERRORED, - project = project, + projectId = e.job.projectId, batchJob = job, ), source = e, - responsibleUser = null, - ) + responsibleUserId = null, + ), ) } } diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt index 4d278499df..b88552afcd 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt @@ -84,10 +84,10 @@ interface LanguageRepository : JpaRepository { SELECT new map(t.id as translationId, t.language.id as languageId) FROM Translation t WHERE t.id IN :translationIds - """ + """, ) fun findLanguageIdsOfTranslations(translationIds: List): List> - @Query("SELECT l.id FROM Language l, Project p WHERE p = :project AND l = p.baseLanguage") - fun getBaseLanguageForProject(project: Project): Long? + @Query("SELECT l.id FROM Language l, Project p WHERE p.id = :projectId AND l = p.baseLanguage") + fun getBaseLanguageForProjectId(projectId: Long): Long? } diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt index 7888dfc6dc..5ef1e2b7f0 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt @@ -4,6 +4,7 @@ import io.tolgee.model.UserAccount import io.tolgee.model.views.UserAccountInProjectView import io.tolgee.model.views.UserAccountProjectPermissionsNotificationPreferencesDataView import io.tolgee.model.views.UserAccountWithOrganizationRoleView +import io.tolgee.model.views.UserProjectMetadataView import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable import org.springframework.data.jpa.repository.JpaRepository @@ -184,41 +185,35 @@ interface UserAccountRepository : JpaRepository { @Query( """ - SELECT new io.tolgee.model.views.UserAccountProjectPermissionsNotificationPreferencesDataView( + SELECT new io.tolgee.model.views.UserProjectMetadataView( ua.id, p.id, org_r.type, - perm_org.type, - perm_org._scopes, - perm.type, - perm._scopes, - array_to_string(array_agg(l.id), ','), + perm_org, + perm, np_global, np_project ) - FROM UserAccount ua, Project p + FROM UserAccount ua + LEFT JOIN Project p ON p.id = :projectId LEFT JOIN OrganizationRole org_r ON org_r.user = ua AND org_r.organization = p.organizationOwner - LEFT JOIN Permission perm ON + LEFT JOIN FETCH Permission perm ON perm.user = ua AND perm.project = p - LEFT JOIN Permission perm_org ON + LEFT JOIN FETCH Permission perm_org ON org_r.user = ua AND org_r.organization = p.organizationOwner AND perm_org.organization = p.organizationOwner - LEFT JOIN Language l ON l IN elements(perm.viewLanguages) LEFT JOIN FETCH NotificationPreferences np_global ON np_global.userAccount = ua AND np_global.project IS NULL LEFT JOIN FETCH NotificationPreferences np_project ON np_project.userAccount = ua AND np_project.project = p WHERE - p.id = :projectId AND ua.deletedAt IS NULL AND ( - (perm._scopes IS NOT NULL AND perm._scopes != '{}') OR perm.type IS NOT NULL OR - (perm_org._scopes IS NOT NULL AND perm_org._scopes != '{}') OR perm_org.type IS NOT NULL + (perm._scopes IS NOT NULL AND cast(perm._scopes as string) != '{}') OR perm.type IS NOT NULL OR + (perm_org._scopes IS NOT NULL AND cast(perm_org._scopes as string) != '{}') OR perm_org.type IS NOT NULL ) - GROUP BY ua.id, p.id, org_r.type, perm_org.type, perm_org._scopes, perm.type, perm._scopes, np_global, np_project - """ + """, ) - fun findAllPermittedUsersProjectPermissionNotificationPreferencesView(projectId: Long): - List + fun findAllUserProjectMetadataViews(projectId: Long): List } diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/notifications/NotificationPreferencesRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/notifications/NotificationPreferencesRepository.kt index 8ba4e98896..a3b5b3883b 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/notifications/NotificationPreferencesRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/notifications/NotificationPreferencesRepository.kt @@ -26,9 +26,15 @@ import org.springframework.stereotype.Repository interface NotificationPreferencesRepository : JpaRepository { fun findAllByUserAccountId(user: Long): List - fun findByUserAccountIdAndProjectId(user: Long, project: Long?): NotificationPreferences? + fun findByUserAccountIdAndProjectId( + user: Long, + project: Long?, + ): NotificationPreferences? - fun deleteByUserAccountIdAndProjectId(user: Long, project: Long) + fun deleteByUserAccountIdAndProjectId( + user: Long, + project: Long, + ) @Modifying @Query("DELETE FROM NotificationPreferences WHERE userAccount.id = :userId") diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt index 4fc2b871c7..4ce5d57822 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt @@ -40,7 +40,7 @@ interface UserNotificationRepository : JpaRepository { ('READ' IN :status AND un.unread = false AND un.markedDoneAt IS NULL) OR ('DONE' IN :status AND un.markedDoneAt IS NOT NULL) ) - """ + """, ) fun findNotificationsOfUserFilteredPaged( recipient: Long, @@ -54,13 +54,13 @@ interface UserNotificationRepository : JpaRepository { WHERE un.unread = true AND un.type = :type AND - un.project = :project AND + un.project.id = :projectId AND un.recipient IN :recipients - """ + """, ) fun findCandidatesForNotificationDebouncing( type: NotificationType, - project: Project, + projectId: Long, recipients: Collection, ): List @@ -71,7 +71,7 @@ interface UserNotificationRepository : JpaRepository { INNER JOIN un.modifiedEntities me WHERE un.unread = true AND - un.project = :project AND + un.project.id = :projectId AND un.recipient IN :recipients AND ( un.type = :type OR ( un.type = io.tolgee.notifications.NotificationType.ACTIVITY_KEYS_CREATED AND @@ -80,11 +80,11 @@ interface UserNotificationRepository : JpaRepository { ) ) ORDER BY un.type DESC - """ + """, ) fun findCandidatesForTranslationUpdateNotificationDebouncing( type: NotificationType, - project: Project, + projectId: Long, recipients: Collection, keyId: Long, ): List @@ -100,23 +100,26 @@ interface UserNotificationRepository : JpaRepository { me.entityClass = 'TranslationComment' AND de.entityClass = 'Translation' AND de.entityId = :translationId AND - un.project = :project AND + un.project.id = :projectId AND un.recipient IN :recipients AND un.type IN ( io.tolgee.notifications.NotificationType.ACTIVITY_NEW_COMMENTS, io.tolgee.notifications.NotificationType.ACTIVITY_COMMENTS_MENTION ) - """ + """, ) fun findCandidatesForCommentNotificationDebouncing( - project: Project, + projectId: Long, recipients: Collection, translationId: Long, ): List @Modifying @Query("UPDATE UserNotification un SET un.unread = false WHERE un.recipient.id = ?1 AND un.id IN ?2") - fun markAsRead(recipient: Long, notifications: Collection) + fun markAsRead( + recipient: Long, + notifications: Collection, + ) @Modifying @Query("UPDATE UserNotification un SET un.unread = false WHERE un.recipient.id = ?1") @@ -124,25 +127,40 @@ interface UserNotificationRepository : JpaRepository { @Modifying @Query("UPDATE UserNotification un SET un.unread = true WHERE un.recipient.id = ?1 AND un.id IN ?2") - fun markAsUnread(recipient: Long, notifications: Collection) + fun markAsUnread( + recipient: Long, + notifications: Collection, + ) @Modifying @Query( """ UPDATE UserNotification un - SET un.unread = false, un.markedDoneAt = NOW() + SET un.unread = false, un.markedDoneAt = CURRENT_TIMESTAMP() WHERE un.recipient.id = ?1 AND un.id IN ?2 - """ + """, + ) + fun markAsDone( + recipient: Long, + notifications: Collection, ) - fun markAsDone(recipient: Long, notifications: Collection) @Modifying - @Query("UPDATE UserNotification un SET un.unread = false, un.markedDoneAt = NOW() WHERE un.recipient.id = ?1") + @Query( + """ + UPDATE UserNotification un + SET un.unread = false, un.markedDoneAt = CURRENT_TIMESTAMP() + WHERE un.recipient.id = ?1 + """ + ) fun markAllAsDone(recipient: Long) @Modifying @Query("UPDATE UserNotification un SET un.markedDoneAt = null WHERE un.recipient.id = ?1 AND un.id IN ?2") - fun unmarkAsDone(recipient: Long, notifications: Collection) + fun unmarkAsDone( + recipient: Long, + notifications: Collection, + ) @Modifying @Query("DELETE FROM user_notification WHERE marked_done_at < NOW() - INTERVAL '90 DAY'", nativeQuery = true) diff --git a/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt b/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt index d637df6c39..272b5aca5e 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt @@ -417,8 +417,7 @@ class LanguageService( return languageRepository.save(language) } - fun getBaseLanguageForProject(project: Project): Long? { - if (Hibernate.isInitialized(project)) return project.baseLanguage?.id - return languageRepository.getBaseLanguageForProject(project) + fun getBaseLanguageForProjectId(projectId: Long): Long? { + return languageRepository.getBaseLanguageForProjectId(projectId) } } diff --git a/backend/data/src/main/kotlin/io/tolgee/service/project/ProjectService.kt b/backend/data/src/main/kotlin/io/tolgee/service/project/ProjectService.kt index d4376eaeea..9d9ef931d9 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/project/ProjectService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/project/ProjectService.kt @@ -286,7 +286,9 @@ class ProjectService( traceLogMeasureTime("deleteProject: delete keys") { keyService.deleteAllByProject(project.id) - }avatarService.unlinkAvatarFiles(project) + } + + avatarService.unlinkAvatarFiles(project) batchJobService.deleteAllByProjectId(project.id) bigMetaService.deleteAllByProjectId(project.id) diff --git a/backend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.kt b/backend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.kt index 1975e715cb..67c172d08e 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.kt @@ -23,6 +23,7 @@ import io.tolgee.model.enums.OrganizationRoleType import io.tolgee.model.enums.ProjectPermissionType import io.tolgee.model.enums.Scope import io.tolgee.model.views.UserAccountProjectPermissionsNotificationPreferencesDataView +import io.tolgee.model.views.UserProjectMetadataView import io.tolgee.repository.PermissionRepository import io.tolgee.service.CachedPermissionService import io.tolgee.service.LanguageService @@ -195,7 +196,7 @@ class PermissionService( fun computeProjectPermission( organizationRole: OrganizationRoleType?, - organizationBasePermission: IPermission, + organizationBasePermission: IPermission?, directPermission: IPermission?, userRole: UserAccount.Role? = null, ): ComputedPermissionDto { @@ -203,7 +204,7 @@ class PermissionService( when { organizationRole == OrganizationRoleType.OWNER -> ComputedPermissionDto.ORGANIZATION_OWNER directPermission != null -> ComputedPermissionDto(directPermission, ComputedPermissionOrigin.DIRECT) - organizationRole == OrganizationRoleType.MEMBER -> + organizationRole == OrganizationRoleType.MEMBER && organizationBasePermission != null -> ComputedPermissionDto( organizationBasePermission, ComputedPermissionOrigin.ORGANIZATION_BASE, @@ -217,35 +218,11 @@ class PermissionService( } ?: computed } - fun computeProjectPermission( - projectPermissionDataView: UserAccountProjectPermissionsNotificationPreferencesDataView - ): ComputedPermissionDto { - val basePermissions = ComputedPermissionDto.getEmptyPermission( - type = projectPermissionDataView.basePermissionsBasic, - scopes = projectPermissionDataView.basePermissionsGranular?.toTypedArray() - ?: projectPermissionDataView.basePermissionsBasic?.availableScopes - ?: emptyArray(), - ) - - if (projectPermissionDataView.permissionsBasic == null && projectPermissionDataView.permissionsGranular == null) { - return computeProjectPermission( - projectPermissionDataView.organizationRole, - basePermissions, - directPermission = null, - ) - } - - val directPermissions = ComputedPermissionDto.getEmptyPermission( - type = projectPermissionDataView.permissionsBasic, - scopes = projectPermissionDataView.permissionsGranular?.toTypedArray() - ?: projectPermissionDataView.permissionsBasic?.availableScopes - ?: emptyArray() - ) - + fun computeProjectPermission(userProjectMetadataView: UserProjectMetadataView): ComputedPermissionDto { return computeProjectPermission( - projectPermissionDataView.organizationRole, - basePermissions, - directPermissions, + userProjectMetadataView.organizationRole, + userProjectMetadataView.basePermissions, + userProjectMetadataView.permissions, ) } diff --git a/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt b/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt index 062d7f8f92..00372a131e 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt @@ -20,6 +20,7 @@ import io.tolgee.model.views.ExtendedUserAccountInProject import io.tolgee.model.views.UserAccountInProjectView import io.tolgee.model.views.UserAccountProjectPermissionsNotificationPreferencesDataView import io.tolgee.model.views.UserAccountWithOrganizationRoleView +import io.tolgee.model.views.UserProjectMetadataView import io.tolgee.notifications.NotificationPreferencesService import io.tolgee.notifications.UserNotificationService import io.tolgee.repository.UserAccountRepository @@ -167,8 +168,8 @@ class UserAccountService( entityManager.remove(it) } - userNotificationService.deleteAllByUserId(userAccount.id) - notificationPreferencesService.deleteAllByUserId(userAccount.id) + userNotificationService.deleteAllByUserId(toDelete.id) + notificationPreferencesService.deleteAllByUserId(toDelete.id) userAccountRepository.softDeleteUser(toDelete, currentDateProvider.date) applicationEventPublisher.publishEvent(OnUserCountChanged(this)) @@ -341,9 +342,8 @@ class UserAccountService( } } - fun getAllPermissionInformationOfPermittedUsersInProject(projectId: Long): - List { - return userAccountRepository.findAllPermittedUsersProjectPermissionNotificationPreferencesView(projectId) + fun getAllConnectedUserProjectMetadataViews(projectId: Long): List { + return userAccountRepository.findAllUserProjectMetadataViews(projectId) } @Transactional @@ -466,7 +466,7 @@ class UserAccountService( this.applicationEventPublisher.publishEvent(OnUserCountChanged(this)) } - private fun transferLegacyNoAuthUser() { + fun transferLegacyNoAuthUser() { val legacyImplicitUser = findActive("___implicit_user") ?: return diff --git a/backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/NotificationsE2eDataController.kt b/backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/NotificationsE2eDataController.kt index 86455df2e9..0a5bcdb11f 100644 --- a/backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/NotificationsE2eDataController.kt +++ b/backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/NotificationsE2eDataController.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.tolgee.controllers.internal.e2e_data +package io.tolgee.controllers.internal.e2eData import io.swagger.v3.oas.annotations.Hidden import io.tolgee.development.testDataBuilder.builders.TestDataBuilder diff --git a/backend/testing/src/main/kotlin/io/tolgee/fixtures/statusExpectations.kt b/backend/testing/src/main/kotlin/io/tolgee/fixtures/statusExpectations.kt index 13cc452477..46202e0c94 100644 --- a/backend/testing/src/main/kotlin/io/tolgee/fixtures/statusExpectations.kt +++ b/backend/testing/src/main/kotlin/io/tolgee/fixtures/statusExpectations.kt @@ -67,7 +67,7 @@ fun ResultActions.andAssertThatJson(jsonAssert: JsonAssert.ConfigurableJsonAsser val diff = if (a > b) a - b else b - a diff <= (tolerance ?: BigDecimal.ZERO) } - } + }, ) this diff --git a/backend/testing/src/main/kotlin/io/tolgee/testing/satisfies.kt b/backend/testing/src/main/kotlin/io/tolgee/testing/satisfies.kt index a56414eb6b..977e902946 100644 --- a/backend/testing/src/main/kotlin/io/tolgee/testing/satisfies.kt +++ b/backend/testing/src/main/kotlin/io/tolgee/testing/satisfies.kt @@ -26,7 +26,9 @@ fun , E> AbstractAssert.satisfies(fn: (actual: E) } fun , E> AbstractAssert.satisfiesIf(fn: (actual: E) -> Boolean): S { - return satisfies(object : Condition() { - override fun matches(value: E): Boolean = fn(value) - }) + return satisfies( + object : Condition() { + override fun matches(value: E): Boolean = fn(value) + }, + ) } From 16986700b47749f5a5b51c08b50e437e35e10e36 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Fri, 26 Jan 2024 17:53:16 +0100 Subject: [PATCH 23/44] chore: format --- .../notifications/AbstractNotificationTest.kt | 2 +- .../UserNotificationDebounceTest.kt | 2 +- .../main/kotlin/io/tolgee/model/Permission.kt | 18 ++--- ...missionsNotificationPreferencesDataView.kt | 75 +++++++++---------- .../model/views/UserProjectMetadataView.kt | 24 +++--- .../notifications/UserNotificationService.kt | 2 +- .../dispatchers/UserNotificationDispatch.kt | 18 ++--- .../dto/NotificationCreateDto.kt | 5 +- .../events/NotificationCreateEvent.kt | 1 - .../listeners/ActivityEventListener.kt | 5 +- .../listeners/BatchJobListener.kt | 1 - .../repository/UserAccountRepository.kt | 1 - .../UserNotificationRepository.kt | 7 +- .../io/tolgee/service/LanguageService.kt | 1 - .../tolgee/service/project/ProjectService.kt | 15 ++-- .../service/security/PermissionService.kt | 5 +- .../service/security/UserAccountService.kt | 1 - 17 files changed, 84 insertions(+), 99 deletions(-) diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt index 79288afb14..3596968f7b 100644 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt @@ -55,7 +55,7 @@ abstract class AbstractNotificationTest : AuthorizedControllerTest() { entityManager.refresh(it.arguments[0]) - println("Dispatched!") + println("Dispatched!") // Wait a bit to make sure everything's *actually* persisted // Kind of an ugly way to synchronize everything, but it is what it is taskScheduler.schedule( diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt index fba8d75986..24eb7466ec 100644 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt @@ -58,7 +58,7 @@ class UserNotificationDebounceTest : AbstractNotificationTest() { performAuthPost( url = "/v2/projects/${testData.calmProject.id}/languages", content = - LanguageRequest( + LanguageRequest( name = "Meow", originalName = "meow", tag = "meow-en", diff --git a/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt b/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt index 03651eaab9..89e391cd9e 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt @@ -135,19 +135,19 @@ class Permission( override val organizationId: Long? get() = this.organization?.id - @ElementCollection(fetch = FetchType.EAGER) - @CollectionTable(name = "permission_languages", joinColumns = [JoinColumn(name = "permission_id")]) - @Column(name = "languages_id") + @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable(name = "permission_languages", joinColumns = [JoinColumn(name = "permission_id")]) + @Column(name = "languages_id") override val translateLanguageIds: Set? = null - @ElementCollection(fetch = FetchType.EAGER) - @CollectionTable(name = "permission_view_languages", joinColumns = [JoinColumn(name = "permission_id")]) - @Column(name = "view_languages_id") + @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable(name = "permission_view_languages", joinColumns = [JoinColumn(name = "permission_id")]) + @Column(name = "view_languages_id") override val viewLanguageIds: Set? = null - @ElementCollection(fetch = FetchType.EAGER) - @CollectionTable(name = "permission_state_change_languages", joinColumns = [JoinColumn(name = "permission_id")]) - @Column(name = "state_change_languages_id") + @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable(name = "permission_state_change_languages", joinColumns = [JoinColumn(name = "permission_id")]) + @Column(name = "state_change_languages_id") override val stateChangeLanguageIds: Set? = null companion object { diff --git a/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionsNotificationPreferencesDataView.kt b/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionsNotificationPreferencesDataView.kt index 1edae70b07..7d1252e8c1 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionsNotificationPreferencesDataView.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionsNotificationPreferencesDataView.kt @@ -18,7 +18,6 @@ package io.tolgee.model.views import io.tolgee.model.OrganizationRole import io.tolgee.model.Permission -import io.tolgee.model.Project import io.tolgee.model.enums.OrganizationRoleType import io.tolgee.model.enums.ProjectPermissionType import io.tolgee.model.enums.Scope @@ -27,55 +26,53 @@ import jakarta.persistence.Id import jakarta.persistence.OneToMany data class UserProjectMetadata( - @Id - val id: Long, - - @Id - val projectId: Long, - - @OneToMany - val organizationRole: OrganizationRole?, - - @OneToMany - val basePermissions: Permission?, - - @OneToMany - val permissions: Permission?, - - @OneToMany - val globalNotificationPreferences: NotificationPreferences?, - - @OneToMany - val projectNotificationPreferences: NotificationPreferences?, + @Id + val id: Long, + @Id + val projectId: Long, + @OneToMany + val organizationRole: OrganizationRole?, + @OneToMany + val basePermissions: Permission?, + @OneToMany + val permissions: Permission?, + @OneToMany + val globalNotificationPreferences: NotificationPreferences?, + @OneToMany + val projectNotificationPreferences: NotificationPreferences?, ) { - val notificationPreferences - get() = projectNotificationPreferences ?: globalNotificationPreferences + val notificationPreferences + get() = projectNotificationPreferences ?: globalNotificationPreferences } class UserAccountProjectPermissionsNotificationPreferencesDataView(data: Map) { - init { - println(data["permittedViewLanguages"]) - } + init { + println(data["permittedViewLanguages"]) + } - val id = data["id"] as? Long ?: throw IllegalArgumentException() + val id = data["id"] as? Long ?: throw IllegalArgumentException() - val projectId = data["projectId"] as? Long ?: throw IllegalArgumentException() + val projectId = data["projectId"] as? Long ?: throw IllegalArgumentException() - val organizationRole = data["organizationRole"] as? OrganizationRoleType + val organizationRole = data["organizationRole"] as? OrganizationRoleType - val basePermissionsBasic = data["basePermissionsBasic"] as? ProjectPermissionType + val basePermissionsBasic = data["basePermissionsBasic"] as? ProjectPermissionType - val basePermissionsGranular = (data["basePermissionsGranular"] as? Array<*>) - ?.map { enumValueOf((it as? Enum<*>)?.name ?: throw IllegalArgumentException()) } + val basePermissionsGranular = + (data["basePermissionsGranular"] as? Array<*>) + ?.map { enumValueOf((it as? Enum<*>)?.name ?: throw IllegalArgumentException()) } - val permissionsBasic = data["permissionsBasic"] as? ProjectPermissionType + val permissionsBasic = data["permissionsBasic"] as? ProjectPermissionType - val permissionsGranular = (data["permissionsGranular"] as? Array<*>) - ?.map { enumValueOf((it as? Enum<*>)?.name ?: throw IllegalArgumentException()) } + val permissionsGranular = + (data["permissionsGranular"] as? Array<*>) + ?.map { enumValueOf((it as? Enum<*>)?.name ?: throw IllegalArgumentException()) } - val permittedViewLanguages = (data["permittedViewLanguages"] as? Array<*>) - ?.map { (it as? String)?.toLong() ?: throw IllegalArgumentException() } + val permittedViewLanguages = + (data["permittedViewLanguages"] as? Array<*>) + ?.map { (it as? String)?.toLong() ?: throw IllegalArgumentException() } - val notificationPreferences = (data["projectNotificationPreferences"] ?: data["globalNotificationPreferences"]) - as? NotificationPreferences + val notificationPreferences = + (data["projectNotificationPreferences"] ?: data["globalNotificationPreferences"]) + as? NotificationPreferences } diff --git a/backend/data/src/main/kotlin/io/tolgee/model/views/UserProjectMetadataView.kt b/backend/data/src/main/kotlin/io/tolgee/model/views/UserProjectMetadataView.kt index d859caff92..e0247677aa 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/views/UserProjectMetadataView.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/views/UserProjectMetadataView.kt @@ -21,20 +21,14 @@ import io.tolgee.model.enums.OrganizationRoleType import io.tolgee.model.notifications.NotificationPreferences data class UserProjectMetadataView( - val userAccountId: Long, - - val projectId: Long, - - val organizationRole: OrganizationRoleType?, - - val basePermissions: Permission?, - - val permissions: Permission?, - - val globalNotificationPreferences: NotificationPreferences?, - - val projectNotificationPreferences: NotificationPreferences?, + val userAccountId: Long, + val projectId: Long, + val organizationRole: OrganizationRoleType?, + val basePermissions: Permission?, + val permissions: Permission?, + val globalNotificationPreferences: NotificationPreferences?, + val projectNotificationPreferences: NotificationPreferences?, ) { - val notificationPreferences - get() = projectNotificationPreferences ?: globalNotificationPreferences + val notificationPreferences + get() = projectNotificationPreferences ?: globalNotificationPreferences } diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt index 0621d59646..976439015e 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt @@ -29,7 +29,7 @@ import org.springframework.transaction.annotation.Transactional @Service class UserNotificationService( - private val entityManager: EntityManager, + private val entityManager: EntityManager, private val userNotificationRepository: UserNotificationRepository, private val applicationEventPublisher: ApplicationEventPublisher, private val userNotificationDebouncer: UserNotificationDebouncer, diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt index 855938f17d..53f371f36f 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt @@ -17,7 +17,6 @@ package io.tolgee.notifications.dispatchers import io.tolgee.dtos.ComputedPermissionDto -import io.tolgee.model.Permission import io.tolgee.model.Screenshot import io.tolgee.model.UserAccount import io.tolgee.model.activity.ActivityModifiedEntity @@ -98,15 +97,16 @@ class UserNotificationDispatch( } private fun handleActivityNotificationForUser( - e: NotificationCreateEvent, - translationToLanguageMap: Map, - userProjectMetadataView: UserProjectMetadataView, + e: NotificationCreateEvent, + translationToLanguageMap: Map, + userProjectMetadataView: UserProjectMetadataView, ): UserNotificationParamsDto? { - val permissions = permissionService.computeProjectPermission( - userProjectMetadataView.organizationRole, - userProjectMetadataView.basePermissions, - userProjectMetadataView.permissions, - ) + val permissions = + permissionService.computeProjectPermission( + userProjectMetadataView.organizationRole, + userProjectMetadataView.basePermissions, + userProjectMetadataView.permissions, + ) // Filter the entities the user is allowed to see val filteredModifiedEntities = diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt index b69d6a0e5e..96e4745a59 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt @@ -29,7 +29,10 @@ data class NotificationCreateDto( val modifiedEntities: MutableList? = null, val batchJob: BatchJob? = null, ) { - fun toUserNotificationEntity(params: UserNotificationParamsDto, em: EntityManager): UserNotification { + fun toUserNotificationEntity( + params: UserNotificationParamsDto, + em: EntityManager, + ): UserNotification { return UserNotification( type = type, recipient = params.recipient, diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationCreateEvent.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationCreateEvent.kt index b1a6fa9263..ecb6874973 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationCreateEvent.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationCreateEvent.kt @@ -16,7 +16,6 @@ package io.tolgee.notifications.events -import io.tolgee.model.UserAccount import io.tolgee.notifications.dto.NotificationCreateDto data class NotificationCreateEvent( diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt index 75bdfa29e9..9e76b91e2b 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt @@ -19,9 +19,7 @@ package io.tolgee.notifications.listeners import io.tolgee.activity.data.ActivityType import io.tolgee.activity.data.RevisionType import io.tolgee.events.OnProjectActivityStoredEvent -import io.tolgee.model.Project import io.tolgee.model.Screenshot -import io.tolgee.model.UserAccount import io.tolgee.model.activity.ActivityModifiedEntity import io.tolgee.model.enums.TranslationState import io.tolgee.model.key.Key @@ -33,7 +31,6 @@ import io.tolgee.notifications.events.NotificationCreateEvent import io.tolgee.service.LanguageService import io.tolgee.util.Logging import io.tolgee.util.logger -import jakarta.persistence.EntityManager import org.springframework.context.ApplicationEventPublisher import org.springframework.context.event.EventListener import org.springframework.stereotype.Component @@ -267,7 +264,7 @@ class ActivityEventListener( private fun processOutdatedFlagUpdate( projectId: Long, - responsibleUserId: Long?, + responsibleUserId: Long?, e: OnProjectActivityStoredEvent, ) { val outdatedTranslations = diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt index 7b596432c7..be85de420f 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt @@ -17,7 +17,6 @@ package io.tolgee.notifications.listeners import io.tolgee.batch.events.OnBatchJobFailed -import io.tolgee.model.Project import io.tolgee.model.batch.BatchJob import io.tolgee.notifications.NotificationType import io.tolgee.notifications.dto.NotificationCreateDto diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt index 1f583a5785..578c8a72d8 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt @@ -3,7 +3,6 @@ package io.tolgee.repository import io.tolgee.dtos.queryResults.UserAccountView import io.tolgee.model.UserAccount import io.tolgee.model.views.UserAccountInProjectView -import io.tolgee.model.views.UserAccountProjectPermissionsNotificationPreferencesDataView import io.tolgee.model.views.UserAccountWithOrganizationRoleView import io.tolgee.model.views.UserProjectMetadataView import org.springframework.data.domain.Page diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt index 4ce5d57822..dd90944a98 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt @@ -16,7 +16,6 @@ package io.tolgee.repository.notifications -import io.tolgee.model.Project import io.tolgee.model.UserAccount import io.tolgee.model.notifications.UserNotification import io.tolgee.notifications.NotificationType @@ -147,12 +146,12 @@ interface UserNotificationRepository : JpaRepository { @Modifying @Query( - """ + """ UPDATE UserNotification un SET un.unread = false, un.markedDoneAt = CURRENT_TIMESTAMP() WHERE un.recipient.id = ?1 - """ - ) + """, + ) fun markAllAsDone(recipient: Long) @Modifying diff --git a/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt b/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt index 272b5aca5e..2f918baa2b 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/LanguageService.kt @@ -16,7 +16,6 @@ import io.tolgee.service.security.SecurityService import io.tolgee.service.translation.AutoTranslationService import io.tolgee.service.translation.TranslationService import jakarta.persistence.EntityManager -import org.hibernate.Hibernate import org.springframework.beans.factory.annotation.Autowired import org.springframework.cache.annotation.CacheEvict import org.springframework.cache.annotation.Cacheable diff --git a/backend/data/src/main/kotlin/io/tolgee/service/project/ProjectService.kt b/backend/data/src/main/kotlin/io/tolgee/service/project/ProjectService.kt index 9d9ef931d9..01b9cc377e 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/project/ProjectService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/project/ProjectService.kt @@ -67,7 +67,7 @@ class ProjectService( @Lazy private val batchJobService: BatchJobService, @Lazy private val userNotificationService: UserNotificationService, @Lazy private val notificationPreferencesService: NotificationPreferencesService, - private val currentDateProvider: CurrentDateProvider, + private val currentDateProvider: CurrentDateProvider, ) : Logging { @set:Autowired @set:Lazy @@ -288,14 +288,15 @@ class ProjectService( keyService.deleteAllByProject(project.id) } - avatarService.unlinkAvatarFiles(project) - batchJobService.deleteAllByProjectId(project.id) - bigMetaService.deleteAllByProjectId(project.id) + avatarService.unlinkAvatarFiles(project) + batchJobService.deleteAllByProjectId(project.id) + bigMetaService.deleteAllByProjectId(project.id) - userNotificationService.deleteAllByProjectId(project.id) - notificationPreferencesService.deleteAllByProjectId(project.id) + userNotificationService.deleteAllByProjectId(project.id) + notificationPreferencesService.deleteAllByProjectId(project.id) - projectRepository.delete(project)} + projectRepository.delete(project) + } } /** diff --git a/backend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.kt b/backend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.kt index 67c172d08e..8cabe33960 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.kt @@ -22,7 +22,6 @@ import io.tolgee.model.UserAccount import io.tolgee.model.enums.OrganizationRoleType import io.tolgee.model.enums.ProjectPermissionType import io.tolgee.model.enums.Scope -import io.tolgee.model.views.UserAccountProjectPermissionsNotificationPreferencesDataView import io.tolgee.model.views.UserProjectMetadataView import io.tolgee.repository.PermissionRepository import io.tolgee.service.CachedPermissionService @@ -221,8 +220,8 @@ class PermissionService( fun computeProjectPermission(userProjectMetadataView: UserProjectMetadataView): ComputedPermissionDto { return computeProjectPermission( userProjectMetadataView.organizationRole, - userProjectMetadataView.basePermissions, - userProjectMetadataView.permissions, + userProjectMetadataView.basePermissions, + userProjectMetadataView.permissions, ) } diff --git a/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt b/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt index 56236fea50..b923439708 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt @@ -19,7 +19,6 @@ import io.tolgee.exceptions.PermissionException import io.tolgee.model.UserAccount import io.tolgee.model.views.ExtendedUserAccountInProject import io.tolgee.model.views.UserAccountInProjectView -import io.tolgee.model.views.UserAccountProjectPermissionsNotificationPreferencesDataView import io.tolgee.model.views.UserAccountWithOrganizationRoleView import io.tolgee.model.views.UserProjectMetadataView import io.tolgee.notifications.NotificationPreferencesService From cda133540d611a0c6ac64698b9011a62b540274c Mon Sep 17 00:00:00 2001 From: Cynthia Date: Fri, 26 Jan 2024 18:14:23 +0100 Subject: [PATCH 24/44] fix(tests): handle bad transactions --- .../V2ProjectsControllerInvitationTest.kt | 18 ++++++++++++------ .../V2ProjectsInvitationControllerEeTest.kt | 6 ++++-- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/V2ProjectsControllerInvitationTest.kt b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/V2ProjectsControllerInvitationTest.kt index 4eddf66cb7..79d1cad276 100644 --- a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/V2ProjectsControllerInvitationTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/V2ProjectsControllerInvitationTest.kt @@ -83,9 +83,12 @@ class V2ProjectsControllerInvitationTest : ProjectAuthControllerTest("/v2/projec type = ProjectPermissionType.TRANSLATE languages = setOf(getLang("en")) }.andIsOk - val invitation = invitationTestUtil.getInvitation(result) - invitation.permission?.translateLanguages!!.map { it.tag }.assert.contains("en") // stores - invitation.permission?.viewLanguages!!.map { it.tag }.assert.contains() // ads also to view + + executeInNewTransaction { + val invitation = invitationTestUtil.getInvitation(result) + invitation.permission?.translateLanguages!!.map { it.tag }.assert.contains("en") // stores + invitation.permission?.viewLanguages!!.map { it.tag }.assert.contains() // ads also to view + } } @Test @@ -97,9 +100,12 @@ class V2ProjectsControllerInvitationTest : ProjectAuthControllerTest("/v2/projec translateLanguages = setOf(getLang("en")) stateChangeLanguages = setOf(getLang("en")) }.andIsOk - val invitation = invitationTestUtil.getInvitation(result) - invitation.permission?.stateChangeLanguages!!.map { it.tag }.assert.contains("en") // stores - invitation.permission?.viewLanguages!!.map { it.tag }.assert.contains() // ads also to view + + executeInNewTransaction { + val invitation = invitationTestUtil.getInvitation(result) + invitation.permission?.stateChangeLanguages!!.map { it.tag }.assert.contains("en") // stores + invitation.permission?.viewLanguages!!.map { it.tag }.assert.contains() // ads also to view + } } @Test diff --git a/ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/V2ProjectsInvitationControllerEeTest.kt b/ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/V2ProjectsInvitationControllerEeTest.kt index fbbdede5ad..316e9b7a32 100644 --- a/ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/V2ProjectsInvitationControllerEeTest.kt +++ b/ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/V2ProjectsInvitationControllerEeTest.kt @@ -59,8 +59,10 @@ class V2ProjectsInvitationControllerEeTest : ProjectAuthControllerTest("/v2/proj translateLanguages = setOf(getLang("en")) }.andIsOk - val invitation = invitationTestUtil.getInvitation(result) - invitation.permission!!.translateLanguages.map { it.tag }.assert.containsExactlyInAnyOrder("en") + executeInNewTransaction { + val invitation = invitationTestUtil.getInvitation(result) + invitation.permission!!.translateLanguages.map { it.tag }.assert.containsExactlyInAnyOrder("en") + } } @Test From b838b7f0e0ec0162ed7a84b67fdb277fda30c164 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Sat, 27 Jan 2024 14:51:59 +0100 Subject: [PATCH 25/44] fix: make language permission fetching more efficient --- .../io/tolgee/cache/AbstractCacheTest.kt | 2 +- .../main/kotlin/io/tolgee/model/Permission.kt | 72 +++++++++++++++---- .../model/views/UserProjectMetadataView.kt | 33 +++++++-- .../tolgee/repository/PermissionRepository.kt | 15 +++- .../repository/UserAccountRepository.kt | 6 +- .../tolgee/service/CachedPermissionService.kt | 2 +- .../service/security/UserAccountService.kt | 1 + gradle.properties | 2 +- 8 files changed, 105 insertions(+), 28 deletions(-) diff --git a/backend/app/src/test/kotlin/io/tolgee/cache/AbstractCacheTest.kt b/backend/app/src/test/kotlin/io/tolgee/cache/AbstractCacheTest.kt index 983224bee9..3b3253885a 100644 --- a/backend/app/src/test/kotlin/io/tolgee/cache/AbstractCacheTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/cache/AbstractCacheTest.kt @@ -122,7 +122,7 @@ abstract class AbstractCacheTest : AbstractSpringTest() { fun `caches permission by project and user`() { val permission = Permission(id = 1) whenever(permissionRepository.findOneByProjectIdAndUserIdAndOrganizationId(1, 1)) - .then { permission } + .then { Permission.PermissionWithLanguageIdsWrapper(permission, null, null, null) } permissionService.find(1, 1) Mockito.verify(permissionRepository, times(1)) .findOneByProjectIdAndUserIdAndOrganizationId(1, 1) diff --git a/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt b/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt index 89e391cd9e..4c2a6490eb 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt @@ -5,9 +5,7 @@ import io.tolgee.dtos.cacheable.IPermission import io.tolgee.dtos.request.project.LanguagePermissions import io.tolgee.model.enums.ProjectPermissionType import io.tolgee.model.enums.Scope -import jakarta.persistence.CollectionTable import jakarta.persistence.Column -import jakarta.persistence.ElementCollection import jakarta.persistence.Entity import jakarta.persistence.EntityListeners import jakarta.persistence.EnumType @@ -23,6 +21,7 @@ import jakarta.persistence.ManyToOne import jakarta.persistence.OneToOne import jakarta.persistence.PrePersist import jakarta.persistence.PreUpdate +import org.hibernate.Hibernate import org.hibernate.annotations.Parameter import org.hibernate.annotations.Type @@ -135,20 +134,41 @@ class Permission( override val organizationId: Long? get() = this.organization?.id - @ElementCollection(fetch = FetchType.EAGER) - @CollectionTable(name = "permission_languages", joinColumns = [JoinColumn(name = "permission_id")]) - @Column(name = "languages_id") - override val translateLanguageIds: Set? = null + @Transient + private var fetchedViewLanguageIds: Set? = null - @ElementCollection(fetch = FetchType.EAGER) - @CollectionTable(name = "permission_view_languages", joinColumns = [JoinColumn(name = "permission_id")]) - @Column(name = "view_languages_id") - override val viewLanguageIds: Set? = null + @Transient + private var fetchedTranslateLanguageIds: Set? = null - @ElementCollection(fetch = FetchType.EAGER) - @CollectionTable(name = "permission_state_change_languages", joinColumns = [JoinColumn(name = "permission_id")]) - @Column(name = "state_change_languages_id") - override val stateChangeLanguageIds: Set? = null + @Transient + private var fetchedStateChangeLanguageIds: Set? = null + + override val viewLanguageIds: Set? + get() { + if (fetchedViewLanguageIds == null || Hibernate.isInitialized(this.viewLanguages)) { + return this.viewLanguages.map { it.id }.toSet() + } + + return fetchedViewLanguageIds + } + + override val translateLanguageIds: Set? + get() { + if (fetchedTranslateLanguageIds == null || Hibernate.isInitialized(this.translateLanguages)) { + return this.translateLanguages.map { it.id }.toSet() + } + + return fetchedTranslateLanguageIds + } + + override val stateChangeLanguageIds: Set? + get() { + if (fetchedStateChangeLanguageIds == null || Hibernate.isInitialized(this.stateChangeLanguages)) { + return this.stateChangeLanguages.map { it.id }.toSet() + } + + return fetchedStateChangeLanguageIds + } companion object { class PermissionListeners { @@ -172,4 +192,28 @@ class Permission( } } } + + class PermissionWithLanguageIdsWrapper( + val permission: Permission, + fetchedViewLanguageIds: Any?, + fetchedTranslateLanguageIds: Any?, + fetchedStateChangeLanguageIds: Any?, + ) { + init { + permission.fetchedViewLanguageIds = (fetchedViewLanguageIds as? Array<*>) + ?.mapNotNull { e -> e as? Long } + ?.toSet() + ?: emptySet() + + permission.fetchedTranslateLanguageIds = (fetchedTranslateLanguageIds as? Array<*>) + ?.mapNotNull { e -> e as? Long } + ?.toSet() + ?: emptySet() + + permission.fetchedStateChangeLanguageIds = (fetchedStateChangeLanguageIds as? Array<*>) + ?.mapNotNull { e -> e as? Long } + ?.toSet() + ?: emptySet() + } + } } diff --git a/backend/data/src/main/kotlin/io/tolgee/model/views/UserProjectMetadataView.kt b/backend/data/src/main/kotlin/io/tolgee/model/views/UserProjectMetadataView.kt index e0247677aa..44de29c1fb 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/views/UserProjectMetadataView.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/views/UserProjectMetadataView.kt @@ -20,15 +20,34 @@ import io.tolgee.model.Permission import io.tolgee.model.enums.OrganizationRoleType import io.tolgee.model.notifications.NotificationPreferences -data class UserProjectMetadataView( +class UserProjectMetadataView( val userAccountId: Long, val projectId: Long, val organizationRole: OrganizationRoleType?, - val basePermissions: Permission?, - val permissions: Permission?, - val globalNotificationPreferences: NotificationPreferences?, - val projectNotificationPreferences: NotificationPreferences?, + basePermissions: Permission?, + fetchedBaseViewLanguages: Any?, + permissions: Permission?, + fetchedViewLanguages: Any?, + globalNotificationPreferences: NotificationPreferences?, + projectNotificationPreferences: NotificationPreferences?, ) { - val notificationPreferences - get() = projectNotificationPreferences ?: globalNotificationPreferences + val notificationPreferences = projectNotificationPreferences ?: globalNotificationPreferences + + val basePermissions = basePermissions?.let { + Permission.PermissionWithLanguageIdsWrapper( + basePermissions, + fetchedBaseViewLanguages, + null, + null + ) + }?.permission + + val permissions = permissions?.let { + Permission.PermissionWithLanguageIdsWrapper( + permissions, + fetchedViewLanguages, + null, + null + ) + }?.permission } diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/PermissionRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/PermissionRepository.kt index 828de80567..191825b18b 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/PermissionRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/PermissionRepository.kt @@ -10,8 +10,17 @@ import org.springframework.stereotype.Repository interface PermissionRepository : JpaRepository { @Query( """ - from Permission p - where + SELECT new io.tolgee.model.Permission${'$'}PermissionWithLanguageIdsWrapper( + p, + array_agg(vl.id) OVER (PARTITION BY p.id), + array_agg(tl.id) OVER (PARTITION BY p.id), + array_agg(sl.id) OVER (PARTITION BY p.id) + ) + FROM Permission p + LEFT JOIN p.viewLanguages vl + LEFT JOIN p.translateLanguages tl + LEFT JOIN p.stateChangeLanguages sl + WHERE ((:projectId is null and p.project.id is null) or p.project.id = :projectId) and ((:userId is null and p.user.id is null) or p.user.id = :userId) and ((:organizationId is null and p.organization.id is null) or p.organization.id = :organizationId) @@ -21,7 +30,7 @@ interface PermissionRepository : JpaRepository { projectId: Long?, userId: Long?, organizationId: Long? = null, - ): Permission? + ): Permission.PermissionWithLanguageIdsWrapper? fun getAllByProjectAndUserNotNull(project: io.tolgee.model.Project?): Set diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt index 578c8a72d8..8566ea0432 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt @@ -204,12 +204,14 @@ interface UserAccountRepository : JpaRepository { @Query( """ - SELECT new io.tolgee.model.views.UserProjectMetadataView( + SELECT DISTINCT new io.tolgee.model.views.UserProjectMetadataView( ua.id, p.id, org_r.type, perm_org, + array_agg(vl_org.id) OVER (PARTITION BY perm_org.id), perm, + array_agg(vl.id) OVER (PARTITION BY perm.id), np_global, np_project ) @@ -221,10 +223,12 @@ interface UserAccountRepository : JpaRepository { LEFT JOIN FETCH Permission perm ON perm.user = ua AND perm.project = p + LEFT JOIN perm.viewLanguages vl LEFT JOIN FETCH Permission perm_org ON org_r.user = ua AND org_r.organization = p.organizationOwner AND perm_org.organization = p.organizationOwner + LEFT JOIN perm_org.viewLanguages vl_org LEFT JOIN FETCH NotificationPreferences np_global ON np_global.userAccount = ua AND np_global.project IS NULL LEFT JOIN FETCH NotificationPreferences np_project ON np_project.userAccount = ua AND np_project.project = p WHERE diff --git a/backend/data/src/main/kotlin/io/tolgee/service/CachedPermissionService.kt b/backend/data/src/main/kotlin/io/tolgee/service/CachedPermissionService.kt index 9cf66c7ff4..e9285cd627 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/CachedPermissionService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/CachedPermissionService.kt @@ -51,7 +51,7 @@ class CachedPermissionService( projectId = projectId, userId = userId, organizationId = organizationId, - )?.let { permission -> + )?.permission?.let { permission -> PermissionDto( id = permission.id, userId = permission.user?.id, diff --git a/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt b/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt index b923439708..6d7e8cbed6 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt @@ -343,6 +343,7 @@ class UserAccountService( } fun getAllConnectedUserProjectMetadataViews(projectId: Long): List { + userAccountRepository.findAllUserProjectMetadataViews(projectId).forEach { println(it.userAccountId) } return userAccountRepository.findAllUserProjectMetadataViews(projectId) } diff --git a/gradle.properties b/gradle.properties index 37bb8ca15e..75119bfea2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ kotlinVersion=1.9.21 springBootVersion=3.1.5 springDocVersion=2.2.0 jjwtVersion=0.11.2 -hibernateVersion=6.4.1.Final +hibernateVersion=6.3.1.Final amazonAwsSdkVersion=2.20.8 springDependencyManagementVersion=1.0.11.RELEASE org.gradle.jvmargs=-Xmx6g -Dkotlin.daemon.jvm.options=-Xmx6g From b841451ba0071cea5f53cd8a71c72d6e2a9ad678 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Sat, 27 Jan 2024 15:08:03 +0100 Subject: [PATCH 26/44] chore: ktlint --- .../V2ProjectsControllerInvitationTest.kt | 20 +++++------ .../model/views/UserProjectMetadataView.kt | 34 ++++++++++--------- .../V2ProjectsInvitationControllerEeTest.kt | 8 ++--- 3 files changed, 32 insertions(+), 30 deletions(-) diff --git a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/V2ProjectsControllerInvitationTest.kt b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/V2ProjectsControllerInvitationTest.kt index 79d1cad276..ebd619db1b 100644 --- a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/V2ProjectsControllerInvitationTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/V2ProjectsControllerInvitationTest.kt @@ -84,11 +84,11 @@ class V2ProjectsControllerInvitationTest : ProjectAuthControllerTest("/v2/projec languages = setOf(getLang("en")) }.andIsOk - executeInNewTransaction { - val invitation = invitationTestUtil.getInvitation(result) - invitation.permission?.translateLanguages!!.map { it.tag }.assert.contains("en") // stores - invitation.permission?.viewLanguages!!.map { it.tag }.assert.contains() // ads also to view - } + executeInNewTransaction { + val invitation = invitationTestUtil.getInvitation(result) + invitation.permission?.translateLanguages!!.map { it.tag }.assert.contains("en") // stores + invitation.permission?.viewLanguages!!.map { it.tag }.assert.contains() // ads also to view + } } @Test @@ -101,11 +101,11 @@ class V2ProjectsControllerInvitationTest : ProjectAuthControllerTest("/v2/projec stateChangeLanguages = setOf(getLang("en")) }.andIsOk - executeInNewTransaction { - val invitation = invitationTestUtil.getInvitation(result) - invitation.permission?.stateChangeLanguages!!.map { it.tag }.assert.contains("en") // stores - invitation.permission?.viewLanguages!!.map { it.tag }.assert.contains() // ads also to view - } + executeInNewTransaction { + val invitation = invitationTestUtil.getInvitation(result) + invitation.permission?.stateChangeLanguages!!.map { it.tag }.assert.contains("en") // stores + invitation.permission?.viewLanguages!!.map { it.tag }.assert.contains() // ads also to view + } } @Test diff --git a/backend/data/src/main/kotlin/io/tolgee/model/views/UserProjectMetadataView.kt b/backend/data/src/main/kotlin/io/tolgee/model/views/UserProjectMetadataView.kt index 44de29c1fb..5ac003fcd9 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/views/UserProjectMetadataView.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/views/UserProjectMetadataView.kt @@ -33,21 +33,23 @@ class UserProjectMetadataView( ) { val notificationPreferences = projectNotificationPreferences ?: globalNotificationPreferences - val basePermissions = basePermissions?.let { - Permission.PermissionWithLanguageIdsWrapper( - basePermissions, - fetchedBaseViewLanguages, - null, - null - ) - }?.permission + val basePermissions = + basePermissions?.let { + Permission.PermissionWithLanguageIdsWrapper( + basePermissions, + fetchedBaseViewLanguages, + null, + null, + ) + }?.permission - val permissions = permissions?.let { - Permission.PermissionWithLanguageIdsWrapper( - permissions, - fetchedViewLanguages, - null, - null - ) - }?.permission + val permissions = + permissions?.let { + Permission.PermissionWithLanguageIdsWrapper( + permissions, + fetchedViewLanguages, + null, + null, + ) + }?.permission } diff --git a/ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/V2ProjectsInvitationControllerEeTest.kt b/ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/V2ProjectsInvitationControllerEeTest.kt index 316e9b7a32..2b470e044f 100644 --- a/ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/V2ProjectsInvitationControllerEeTest.kt +++ b/ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/V2ProjectsInvitationControllerEeTest.kt @@ -59,10 +59,10 @@ class V2ProjectsInvitationControllerEeTest : ProjectAuthControllerTest("/v2/proj translateLanguages = setOf(getLang("en")) }.andIsOk - executeInNewTransaction { - val invitation = invitationTestUtil.getInvitation(result) - invitation.permission!!.translateLanguages.map { it.tag }.assert.containsExactlyInAnyOrder("en") - } + executeInNewTransaction { + val invitation = invitationTestUtil.getInvitation(result) + invitation.permission!!.translateLanguages.map { it.tag }.assert.containsExactlyInAnyOrder("en") + } } @Test From c208be03d197a71c7ebd7553d1024211d61f631a Mon Sep 17 00:00:00 2001 From: Cynthia Date: Sat, 27 Jan 2024 17:18:12 +0100 Subject: [PATCH 27/44] fix: bad aggregation result --- .../io/tolgee/notifications/AbstractNotificationTest.kt | 7 ++----- .../kotlin/io/tolgee/repository/PermissionRepository.kt | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt index 3596968f7b..67714651cf 100644 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt @@ -53,14 +53,11 @@ abstract class AbstractNotificationTest : AuthorizedControllerTest() { entityManager.persist(it.arguments[0]) entityManager.flush() - entityManager.refresh(it.arguments[0]) - - println("Dispatched!") // Wait a bit to make sure everything's *actually* persisted // Kind of an ugly way to synchronize everything, but it is what it is taskScheduler.schedule( { semaphore.release() }, - Date().addMilliseconds(100), + Date().addMilliseconds(100).toInstant(), ) it.arguments[0] @@ -77,7 +74,7 @@ abstract class AbstractNotificationTest : AuthorizedControllerTest() { // Kind of an ugly way to synchronize everything, but it is what it is taskScheduler.schedule( { semaphore.release(list.size) }, - Date().addMilliseconds(100), + Date().addMilliseconds(100).toInstant(), ) it.arguments[0] diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/PermissionRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/PermissionRepository.kt index 191825b18b..7657087732 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/PermissionRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/PermissionRepository.kt @@ -10,7 +10,7 @@ import org.springframework.stereotype.Repository interface PermissionRepository : JpaRepository { @Query( """ - SELECT new io.tolgee.model.Permission${'$'}PermissionWithLanguageIdsWrapper( + SELECT DISTINCT new io.tolgee.model.Permission${'$'}PermissionWithLanguageIdsWrapper( p, array_agg(vl.id) OVER (PARTITION BY p.id), array_agg(tl.id) OVER (PARTITION BY p.id), From 0601b7187d66434b4684a4d175cf55d76c128721 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Sat, 27 Jan 2024 17:36:32 +0100 Subject: [PATCH 28/44] fix: bad permission mock --- .../app/src/test/kotlin/io/tolgee/cache/AbstractCacheTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/app/src/test/kotlin/io/tolgee/cache/AbstractCacheTest.kt b/backend/app/src/test/kotlin/io/tolgee/cache/AbstractCacheTest.kt index 3b3253885a..178cdb821b 100644 --- a/backend/app/src/test/kotlin/io/tolgee/cache/AbstractCacheTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/cache/AbstractCacheTest.kt @@ -137,7 +137,7 @@ abstract class AbstractCacheTest : AbstractSpringTest() { whenever( permissionRepository .findOneByProjectIdAndUserIdAndOrganizationId(null, null, organizationId = 1), - ).then { permission } + ).then { Permission.PermissionWithLanguageIdsWrapper(permission, null, null, null) } permissionService.find(organizationId = 1) Mockito.verify(permissionRepository, times(1)) From 9cb51f49eec4583a2f85d915535df7fa8345214c Mon Sep 17 00:00:00 2001 From: Cynthia Date: Mon, 5 Feb 2024 09:00:02 +0100 Subject: [PATCH 29/44] chore(webapp): cleanup & update some deps --- webapp/package-lock.json | 15194 ++++++++++++++----------------------- webapp/package.json | 15 +- webapp/src/custom.d.ts | 7 - webapp/vite.config.ts | 11 +- 4 files changed, 5734 insertions(+), 9493 deletions(-) diff --git a/webapp/package-lock.json b/webapp/package-lock.json index 41d8c5551f..b995fff888 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -14,16 +14,14 @@ "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", "@formatjs/icu-messageformat-parser": "^2.0.8", - "@mdx-js/rollup": "^3.0.0", "@mui/icons-material": "^5.5.1", "@mui/lab": "^5.0.0-alpha.75", "@mui/material": "^5.5.3", "@mui/x-date-pickers": "5.0.0-beta.6", - "@openreplay/tracker": "^3.5.4", "@sentry/browser": "^7.80.0", "@stomp/stompjs": "^6.1.2", "@tolgee/format-icu": "^5.16.0", - "@tolgee/react": "^5.16.0", + "@tolgee/react": "^5.19.3", "@vitejs/plugin-react": "^4.2.1", "clsx": "^1.1.1", "codemirror": "^5.62.0", @@ -33,14 +31,12 @@ "dotenv-flow": "4.0.1", "formik": "^2.2.9", "intl-messageformat": "^9.8.1", - "node-fetch": "3.3.0", "notistack": "^2.0.4", "posthog-js": "^1.96.1", - "prism-react-renderer": "1.2.1", - "prism-svelte": "0.4.7", + "prism-react-renderer": "^2.3.1", "react": "^17.0.1", "react-codemirror2": "^7.3.0", - "react-cropper": "2.1.8", + "react-cropper": "^2.3.3", "react-dnd": "^14.0.2", "react-dnd-html5-backend": "^14.0.0", "react-dom": "^17.0.2", @@ -54,7 +50,7 @@ "react-query": "^3.39.2", "react-redux": "^7.2.6", "react-router-dom": "^5.2.0", - "recharts": "2.1.9", + "recharts": "^2.11.0", "redux": "^4.1.0", "redux-promise-middleware": "^6.1.2", "redux-thunk": "^2.3.0", @@ -70,7 +66,7 @@ "zxcvbn": "^4.4.2" }, "devDependencies": { - "@mdx-js/loader": "1.6.22", + "@mdx-js/rollup": "^3.0.0", "@sentry/types": "^6.5.1", "@testing-library/jest-dom": "^5.14.1", "@testing-library/react": "^12.0.0", @@ -99,6 +95,7 @@ "rehype-highlight": "^7.0.0", "ts-unused-exports": "^9.0.4", "typescript": "^5.3.3", + "vite": "^5.0.12", "vite-plugin-node-polyfills": "^0.19.0", "vite-plugin-static-copy": "^1.0.0", "vite-plugin-svgr": "^4.2.0", @@ -107,23 +104,20 @@ }, "node_modules/@aashutoshrathi/word-wrap": { "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/@adobe/css-tools": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.2.tgz", - "integrity": "sha512-DA5a1C0gD/pLOvhv33YMrbf2FK3oUzwNl9oOJqE4XVjuEtt6XIakRcsd7eLiOSPkp1kTRQGICTA8cKra/vFbjw==", - "dev": true + "version": "4.3.3", + "dev": true, + "license": "MIT" }, "node_modules/@ampproject/remapping": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -134,8 +128,7 @@ }, "node_modules/@babel/code-frame": { "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "license": "MIT", "dependencies": { "@babel/highlight": "^7.23.4", "chalk": "^2.4.2" @@ -144,29 +137,84 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "license": "MIT" + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/compat-data": { "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", - "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz", - "integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==", + "version": "7.23.9", + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.23.5", "@babel/generator": "^7.23.6", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.7", - "@babel/parser": "^7.23.6", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.7", - "@babel/types": "^7.23.6", + "@babel/helpers": "^7.23.9", + "@babel/parser": "^7.23.9", + "@babel/template": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -181,10 +229,20 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/generator": { "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", - "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "license": "MIT", "dependencies": { "@babel/types": "^7.23.6", "@jridgewell/gen-mapping": "^0.3.2", @@ -197,8 +255,7 @@ }, "node_modules/@babel/helper-compilation-targets": { "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", - "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "license": "MIT", "dependencies": { "@babel/compat-data": "^7.23.5", "@babel/helper-validator-option": "^7.23.5", @@ -210,18 +267,23 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/helper-environment-visitor": { "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "license": "MIT", "dependencies": { "@babel/template": "^7.22.15", "@babel/types": "^7.23.0" @@ -232,8 +294,7 @@ }, "node_modules/@babel/helper-hoist-variables": { "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "license": "MIT", "dependencies": { "@babel/types": "^7.22.5" }, @@ -243,8 +304,7 @@ }, "node_modules/@babel/helper-module-imports": { "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "license": "MIT", "dependencies": { "@babel/types": "^7.22.15" }, @@ -254,8 +314,7 @@ }, "node_modules/@babel/helper-module-transforms": { "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "license": "MIT", "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-module-imports": "^7.22.15", @@ -272,16 +331,14 @@ }, "node_modules/@babel/helper-plugin-utils": { "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "license": "MIT", "dependencies": { "@babel/types": "^7.22.5" }, @@ -291,8 +348,7 @@ }, "node_modules/@babel/helper-split-export-declaration": { "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "license": "MIT", "dependencies": { "@babel/types": "^7.22.5" }, @@ -302,36 +358,32 @@ }, "node_modules/@babel/helper-string-parser": { "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", - "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.7.tgz", - "integrity": "sha512-6AMnjCoC8wjqBzDHkuqpa7jAKwvMo4dC+lr/TFBz+ucfulO1XMpDnwWPGBNwClOKZ8h6xn5N81W/R5OrcKtCbQ==", + "version": "7.23.9", + "license": "MIT", "dependencies": { - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.7", - "@babel/types": "^7.23.6" + "@babel/template": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9" }, "engines": { "node": ">=6.9.0" @@ -339,8 +391,7 @@ }, "node_modules/@babel/highlight": { "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", @@ -350,75 +401,76 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/parser": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", - "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", - "bin": { - "parser": "bin/babel-parser.js" + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=4" } }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz", - "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.", - "dev": true, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-transform-parameters": "^7.12.1" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=4" } }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", - "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", - "dev": true, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "color-name": "1.1.3" } }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "license": "MIT" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "license": "MIT", + "engines": { + "node": ">=0.8.0" } }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz", - "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==", - "dev": true, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "has-flag": "^3.0.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.9", + "license": "MIT", + "bin": { + "parser": "bin/babel-parser.js" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6.0.0" } }, "node_modules/@babel/plugin-transform-react-jsx-self": { "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz", - "integrity": "sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, @@ -431,8 +483,7 @@ }, "node_modules/@babel/plugin-transform-react-jsx-source": { "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz", - "integrity": "sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, @@ -444,9 +495,8 @@ } }, "node_modules/@babel/runtime": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.7.tgz", - "integrity": "sha512-w06OXVOFso7LcbzMiDGt+3X7Rh7Ho8MmgPoWU3rarH+8upf+wSU/grlGbWzQyr3DkdN6ZeuMFjpdwW0Q+HxobA==", + "version": "7.23.9", + "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -456,26 +506,23 @@ }, "node_modules/@babel/runtime/node_modules/regenerator-runtime": { "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + "license": "MIT" }, "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.23.9", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.7.tgz", - "integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==", + "version": "7.23.9", + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.23.5", "@babel/generator": "^7.23.6", @@ -483,8 +530,8 @@ "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.6", - "@babel/types": "^7.23.6", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -493,9 +540,8 @@ } }, "node_modules/@babel/types": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", - "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "version": "7.23.9", + "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.23.4", "@babel/helper-validator-identifier": "^7.22.20", @@ -507,13 +553,11 @@ }, "node_modules/@date-io/core": { "version": "2.17.0", - "resolved": "https://registry.npmjs.org/@date-io/core/-/core-2.17.0.tgz", - "integrity": "sha512-+EQE8xZhRM/hsY0CDTVyayMDDY5ihc4MqXCrPxooKw19yAzUIC6uUqsZeaOFNL9YKTNxYKrJP5DFgE8o5xRCOw==" + "license": "MIT" }, "node_modules/@date-io/date-fns": { "version": "2.17.0", - "resolved": "https://registry.npmjs.org/@date-io/date-fns/-/date-fns-2.17.0.tgz", - "integrity": "sha512-L0hWZ/mTpy3Gx/xXJ5tq5CzHo0L7ry6KEO9/w/JWiFWFLZgiNVo3ex92gOl3zmzjHqY/3Ev+5sehAr8UnGLEng==", + "license": "MIT", "dependencies": { "@date-io/core": "^2.17.0" }, @@ -528,8 +572,7 @@ }, "node_modules/@date-io/dayjs": { "version": "2.17.0", - "resolved": "https://registry.npmjs.org/@date-io/dayjs/-/dayjs-2.17.0.tgz", - "integrity": "sha512-Iq1wjY5XzBh0lheFA0it6Dsyv94e8mTiNR8vuTai+KopxDkreL3YjwTmZHxkgB7/vd0RMIACStzVgWvPATnDCA==", + "license": "MIT", "dependencies": { "@date-io/core": "^2.17.0" }, @@ -544,8 +587,7 @@ }, "node_modules/@date-io/luxon": { "version": "2.17.0", - "resolved": "https://registry.npmjs.org/@date-io/luxon/-/luxon-2.17.0.tgz", - "integrity": "sha512-l712Vdm/uTddD2XWt9TlQloZUiTiRQtY5TCOG45MQ/8u0tu8M17BD6QYHar/3OrnkGybALAMPzCy1r5D7+0HBg==", + "license": "MIT", "dependencies": { "@date-io/core": "^2.17.0" }, @@ -560,8 +602,7 @@ }, "node_modules/@date-io/moment": { "version": "2.17.0", - "resolved": "https://registry.npmjs.org/@date-io/moment/-/moment-2.17.0.tgz", - "integrity": "sha512-e4nb4CDZU4k0WRVhz1Wvl7d+hFsedObSauDHKtZwU9kt7gdYEAzKgnrSCTHsEaXrDumdrkCYTeZ0Tmyk7uV4tw==", + "license": "MIT", "dependencies": { "@date-io/core": "^2.17.0" }, @@ -576,9 +617,7 @@ }, "node_modules/@dicebear/avatars": { "version": "4.10.2", - "resolved": "https://registry.npmjs.org/@dicebear/avatars/-/avatars-4.10.2.tgz", - "integrity": "sha512-7Qd4Mmq9jeMkWtPZgY89GxFZmu1ERSTSTSEbeNfgVzqxZ0M2NHKcc/uynFMpU13w2BGesCDGT3ulmKyCoYbMGA==", - "deprecated": "This package is deprecated. Use '@dicebear/core' instead. Read more: https://dicebear.com/how-to-use/js-library", + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.7", "pure-color": "^1.3.0", @@ -587,18 +626,14 @@ }, "node_modules/@dicebear/avatars-identicon-sprites": { "version": "4.10.2", - "resolved": "https://registry.npmjs.org/@dicebear/avatars-identicon-sprites/-/avatars-identicon-sprites-4.10.2.tgz", - "integrity": "sha512-EI8CL9w3VCZp0KhxFzHh3iuvGR6CZT6CWjxao8urvwNUKEFBBhwI8C1/1bKYG+zWDtMPHkakmlvn/BCSNRl7Qg==", - "deprecated": "This package is deprecated. Use '@dicebear/identicon' instead. Read more: https://dicebear.com/styles/identicon", + "license": "MIT", "peerDependencies": { "@dicebear/avatars": "^4.6.0" } }, "node_modules/@dicebear/avatars-initials-sprites": { "version": "4.10.2", - "resolved": "https://registry.npmjs.org/@dicebear/avatars-initials-sprites/-/avatars-initials-sprites-4.10.2.tgz", - "integrity": "sha512-/i0fnPOV8jideYUz8Dhgrh76pu7f7gATrX1LjbCgMuGyoXj9VwX+F9jJagFxpcqxWANHGd8JvNaA44yno/vysA==", - "deprecated": "This package is deprecated. Use '@dicebear/initials' instead. Read more: https://dicebear.com/styles/initials", + "license": "MIT", "dependencies": { "initials": "^3.0.1" }, @@ -608,8 +643,7 @@ }, "node_modules/@emotion/babel-plugin": { "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", - "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/runtime": "^7.18.3", @@ -624,15 +658,9 @@ "stylis": "4.2.0" } }, - "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" - }, "node_modules/@emotion/cache": { "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", - "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "license": "MIT", "dependencies": { "@emotion/memoize": "^0.8.1", "@emotion/sheet": "^1.2.2", @@ -643,26 +671,22 @@ }, "node_modules/@emotion/hash": { "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", - "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + "license": "MIT" }, "node_modules/@emotion/is-prop-valid": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz", - "integrity": "sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==", + "license": "MIT", "dependencies": { "@emotion/memoize": "^0.8.1" } }, "node_modules/@emotion/memoize": { "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", - "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + "license": "MIT" }, "node_modules/@emotion/react": { "version": "11.11.3", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.3.tgz", - "integrity": "sha512-Cnn0kuq4DoONOMcnoVsTOR8E+AdnKFf//6kUWc4LCdnxj31pZWn7rIULd6Y7/Js1PiPHzn7SKCM9vB/jBni8eA==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.11.0", @@ -684,8 +708,7 @@ }, "node_modules/@emotion/serialize": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.3.tgz", - "integrity": "sha512-iD4D6QVZFDhcbH0RAG1uVu1CwVLMWUkCvAqqlewO/rxf8+87yIBAlt4+AxMiiKPLs5hFc0owNk/sLLAOROw3cA==", + "license": "MIT", "dependencies": { "@emotion/hash": "^0.9.1", "@emotion/memoize": "^0.8.1", @@ -696,13 +719,11 @@ }, "node_modules/@emotion/sheet": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", - "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" + "license": "MIT" }, "node_modules/@emotion/styled": { "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.0.tgz", - "integrity": "sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.11.0", @@ -723,468 +744,144 @@ }, "node_modules/@emotion/unitless": { "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", - "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + "license": "MIT" }, "node_modules/@emotion/use-insertion-effect-with-fallbacks": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", - "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", + "license": "MIT", "peerDependencies": { "react": ">=16.8.0" } }, "node_modules/@emotion/utils": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", - "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + "license": "MIT" }, "node_modules/@emotion/weak-memoize": { "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", - "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + "license": "MIT" }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.11.tgz", - "integrity": "sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g==", + "node_modules/@esbuild/win32-x64": { + "version": "0.19.12", "cpu": [ - "ppc64" + "x64" ], + "license": "MIT", "optional": true, "os": [ - "aix" + "win32" ], - "peer": true, "engines": { "node": ">=12" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.11.tgz", - "integrity": "sha512-5OVapq0ClabvKvQ58Bws8+wkLCV+Rxg7tUVbo9xu034Nm536QTII4YzhaFriQ7rMrorfnFKUsArD2lqKbFY4vw==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ], - "peer": true, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, "engines": { - "node": ">=12" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@esbuild/android-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.11.tgz", - "integrity": "sha512-aiu7K/5JnLj//KOnOfEZ0D90obUkRzDMyqd/wNAUQ34m4YUPVhRZpnqKV9uqDGxT7cToSDnIHsGooyIczu9T+Q==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "peer": true, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@esbuild/android-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.11.tgz", - "integrity": "sha512-eccxjlfGw43WYoY9QgB82SgGgDbibcqyDTlk3l3C0jOVHKxrjdc9CTwDUQd0vkvYg5um0OH+GpxYvp39r+IPOg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "android" - ], - "peer": true, + "node_modules/@eslint/eslintrc": { + "version": "0.4.3", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, "engines": { - "node": ">=12" + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.11.tgz", - "integrity": "sha512-ETp87DRWuSt9KdDVkqSoKoLFHYTrkyz2+65fj9nfXsaV3bMhTCjtQfw3y+um88vGRKRiF7erPrh/ZuIdLUIVxQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": ">=12" + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "1.0.10", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.11.tgz", - "integrity": "sha512-fkFUiS6IUK9WYUO/+22omwetaSNl5/A8giXvQlcinLIjVkxwTLSktbF5f/kJMftM2MJp9+fXqZ5ezS7+SALp4g==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": ">=12" + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.11.tgz", - "integrity": "sha512-lhoSp5K6bxKRNdXUtHoNc5HhbXVCS8V0iZmDvyWvYq9S5WSfTIHU2UGjcGt7UeS6iEYp9eeymIl5mJBn0yiuxA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "peer": true, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, "engines": { - "node": ">=12" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.11.tgz", - "integrity": "sha512-JkUqn44AffGXitVI6/AbQdoYAq0TEullFdqcMY/PCUZ36xJ9ZJRtQabzMA+Vi7r78+25ZIBosLTOKnUXBSi1Kw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "peer": true, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "4.0.6", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">= 4" } }, - "node_modules/@esbuild/linux-arm": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.11.tgz", - "integrity": "sha512-3CRkr9+vCV2XJbjwgzjPtO8T0SZUmRZla+UL1jw+XqHZPkPgZiyWvbDvl9rqAN8Zl7qJF0O/9ycMtjU67HN9/Q==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=12" + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "3.14.1", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.11.tgz", - "integrity": "sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.11.tgz", - "integrity": "sha512-caHy++CsD8Bgq2V5CodbJjFPEiDPq8JJmBdeyZ8GWVQMjRD0sU548nNdwPNvKjVpamYYVL40AORekgfIubwHoA==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.11.tgz", - "integrity": "sha512-ppZSSLVpPrwHccvC6nQVZaSHlFsvCQyjnvirnVjbKSHuE5N24Yl8F3UwYUUR1UEPaFObGD2tSvVKbvR+uT1Nrg==", - "cpu": [ - "loong64" - ], - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.11.tgz", - "integrity": "sha512-B5x9j0OgjG+v1dF2DkH34lr+7Gmv0kzX6/V0afF41FkPMMqaQ77pH7CrhWeR22aEeHKaeZVtZ6yFwlxOKPVFyg==", - "cpu": [ - "mips64el" - ], - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.11.tgz", - "integrity": "sha512-MHrZYLeCG8vXblMetWyttkdVRjQlQUb/oMgBNurVEnhj4YWOr4G5lmBfZjHYQHHN0g6yDmCAQRR8MUHldvvRDA==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.11.tgz", - "integrity": "sha512-f3DY++t94uVg141dozDu4CCUkYW+09rWtaWfnb3bqe4w5NqmZd6nPVBm+qbz7WaHZCoqXqHz5p6CM6qv3qnSSQ==", - "cpu": [ - "riscv64" - ], - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.11.tgz", - "integrity": "sha512-A5xdUoyWJHMMlcSMcPGVLzYzpcY8QP1RtYzX5/bS4dvjBGVxdhuiYyFwp7z74ocV7WDc0n1harxmpq2ePOjI0Q==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.11.tgz", - "integrity": "sha512-grbyMlVCvJSfxFQUndw5mCtWs5LO1gUlwP4CDi4iJBbVpZcqLVT29FxgGuBJGSzyOxotFG4LoO5X+M1350zmPA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.11.tgz", - "integrity": "sha512-13jvrQZJc3P230OhU8xgwUnDeuC/9egsjTkXN49b3GcS5BKvJqZn86aGM8W9pd14Kd+u7HuFBMVtrNGhh6fHEQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "netbsd" - ], - "peer": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.11.tgz", - "integrity": "sha512-ysyOGZuTp6SNKPE11INDUeFVVQFrhcNDVUgSQVDzqsqX38DjhPEPATpid04LCoUr2WXhQTEZ8ct/EgJCUDpyNw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "openbsd" - ], - "peer": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.11.tgz", - "integrity": "sha512-Hf+Sad9nVwvtxy4DXCZQqLpgmRTQqyFyhT3bZ4F2XlJCjxGmRFF0Shwn9rzhOYRB61w9VMXUkxlBy56dk9JJiQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "sunos" - ], - "peer": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.11.tgz", - "integrity": "sha512-0P58Sbi0LctOMOQbpEOvOL44Ne0sqbS0XWHMvvrg6NE5jQ1xguCSSw9jQeUk2lfrXYsKDdOe6K+oZiwKPilYPQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "peer": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.11.tgz", - "integrity": "sha512-6YOrWS+sDJDmshdBIQU+Uoyh7pQKrdykdefC1avn76ss5c+RN6gut3LZA4E2cH5xUEp5/cA0+YxRaVtRAb0xBg==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "peer": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.11.tgz", - "integrity": "sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "peer": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", "dev": true, + "license": "ISC", "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" + "brace-expansion": "^1.1.7" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, "engines": { - "node": ">= 4" + "node": "*" } }, "node_modules/@eslint/eslintrc/node_modules/type-fest": { "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -1194,36 +891,32 @@ }, "node_modules/@fastify/busboy": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", - "integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==", "dev": true, + "license": "MIT", "engines": { "node": ">=14" } }, "node_modules/@floating-ui/core": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.2.tgz", - "integrity": "sha512-Ii3MrfY/GAIN3OhXNzpCKaLxHQfJF9qvwq/kEJYdqDxeIHa01K8sldugal6TmeeXl+WMvhv9cnVzUTaFFJF09A==", + "version": "1.6.0", + "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.1.3" + "@floating-ui/utils": "^0.2.1" } }, "node_modules/@floating-ui/dom": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.3.tgz", - "integrity": "sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==", + "version": "1.6.1", + "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.4.2", - "@floating-ui/utils": "^0.1.3" + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.1" } }, "node_modules/@floating-ui/react-dom": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.4.tgz", - "integrity": "sha512-CF8k2rgKeh/49UrnIBs4BdxPUV6vize/Db1d/YbCLyp9GiVZ0BEwf5AiDSxJRCr6yOkGqTFHtmrULxkEfYZ7dQ==", + "version": "2.0.8", + "license": "MIT", "dependencies": { - "@floating-ui/dom": "^1.5.1" + "@floating-ui/dom": "^1.6.1" }, "peerDependencies": { "react": ">=16.8.0", @@ -1231,68 +924,60 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.6.tgz", - "integrity": "sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==" + "version": "0.2.1", + "license": "MIT" }, "node_modules/@formatjs/ecma402-abstract": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.18.0.tgz", - "integrity": "sha512-PEVLoa3zBevWSCZzPIM/lvPCi8P5l4G+NXQMc/CjEiaCWgyHieUoo0nM7Bs0n/NbuQ6JpXEolivQ9pKSBHaDlA==", + "version": "1.18.2", + "license": "MIT", "dependencies": { - "@formatjs/intl-localematcher": "0.5.2", + "@formatjs/intl-localematcher": "0.5.4", "tslib": "^2.4.0" } }, "node_modules/@formatjs/fast-memoize": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-1.2.1.tgz", - "integrity": "sha512-Rg0e76nomkz3vF9IPlKeV+Qynok0r7YZjL6syLz4/urSg0IbjPZCB/iYUMNsYA643gh4mgrX3T7KEIFIxJBQeg==", + "license": "MIT", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@formatjs/icu-messageformat-parser": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.3.tgz", - "integrity": "sha512-X/jy10V9S/vW+qlplqhMUxR8wErQ0mmIYSq4mrjpjDl9mbuGcCILcI1SUYkL5nlM4PJqpc0KOS0bFkkJNPxYRw==", + "version": "2.7.6", + "license": "MIT", "dependencies": { - "@formatjs/ecma402-abstract": "1.18.0", - "@formatjs/icu-skeleton-parser": "1.7.0", + "@formatjs/ecma402-abstract": "1.18.2", + "@formatjs/icu-skeleton-parser": "1.8.0", "tslib": "^2.4.0" } }, "node_modules/@formatjs/icu-skeleton-parser": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.7.0.tgz", - "integrity": "sha512-Cfdo/fgbZzpN/jlN/ptQVe0lRHora+8ezrEeg2RfrNjyp+YStwBy7cqDY8k5/z2LzXg6O0AdzAV91XS0zIWv+A==", + "version": "1.8.0", + "license": "MIT", "dependencies": { - "@formatjs/ecma402-abstract": "1.18.0", + "@formatjs/ecma402-abstract": "1.18.2", "tslib": "^2.4.0" } }, "node_modules/@formatjs/intl-getcanonicallocales": { "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@formatjs/intl-getcanonicallocales/-/intl-getcanonicallocales-1.9.2.tgz", - "integrity": "sha512-69WTStIJI2ikErOU1Il4NQKLVV8f2x6awr7+/dZz0uihuI7uQRcZtI6k/BBt4EtYaEl6w65YjUF93VuE015C0w==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@formatjs/intl-localematcher": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.2.tgz", - "integrity": "sha512-txaaE2fiBMagLrR4jYhxzFO6wEdEG4TPMqrzBAcbr4HFUYzH/YC+lg6OIzKCHm8WgDdyQevxbAAV1OgcXctuGw==", + "version": "0.5.4", + "license": "MIT", "dependencies": { "tslib": "^2.4.0" } }, "node_modules/@humanwhocodes/config-array": { "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@humanwhocodes/object-schema": "^1.2.0", "debug": "^4.1.1", @@ -1302,102 +987,90 @@ "node": ">=10.10.0" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } }, - "node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", "dev": true, + "license": "ISC", "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">= 10.14.2" + "node": "*" } }, - "node_modules/@jest/types/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", "dev": true, + "license": "ISC", "dependencies": { - "color-convert": "^2.0.1" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, "engines": { - "node": ">=8" + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/@jest/types/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/@jest/types/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@jest/types": { + "version": "26.6.2", "dev": true, + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" }, "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/types/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/types/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/types/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "node": ">= 10.14.2" } }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.0.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -1409,172 +1082,34 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "license": "MIT", "engines": { "node": ">=6.0.0" } }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", - "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "version": "0.3.22", + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@mdx-js/loader": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/@mdx-js/loader/-/loader-1.6.22.tgz", - "integrity": "sha512-9CjGwy595NaxAYp0hF9B/A0lH6C8Rms97e2JS9d3jVUtILn6pT5i5IV965ra3lIWc7Rs1GG1tBdVF7dCowYe6Q==", - "dev": true, - "dependencies": { - "@mdx-js/mdx": "1.6.22", - "@mdx-js/react": "1.6.22", - "loader-utils": "2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/@mdx-js/mdx": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-1.6.22.tgz", - "integrity": "sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA==", - "dev": true, - "dependencies": { - "@babel/core": "7.12.9", - "@babel/plugin-syntax-jsx": "7.12.1", - "@babel/plugin-syntax-object-rest-spread": "7.8.3", - "@mdx-js/util": "1.6.22", - "babel-plugin-apply-mdx-type-prop": "1.6.22", - "babel-plugin-extract-import-names": "1.6.22", - "camelcase-css": "2.0.1", - "detab": "2.0.4", - "hast-util-raw": "6.0.1", - "lodash.uniq": "4.5.0", - "mdast-util-to-hast": "10.0.1", - "remark-footnotes": "2.0.0", - "remark-mdx": "1.6.22", - "remark-parse": "8.0.3", - "remark-squeeze-paragraphs": "4.0.0", - "style-to-object": "0.3.0", - "unified": "9.2.0", - "unist-builder": "2.0.3", - "unist-util-visit": "2.0.3" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/@mdx-js/mdx/node_modules/@babel/core": { - "version": "7.12.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", - "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.5", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helpers": "^7.12.5", - "@babel/parser": "^7.12.7", - "@babel/template": "^7.12.7", - "@babel/traverse": "^7.12.9", - "@babel/types": "^7.12.7", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@mdx-js/mdx/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/@mdx-js/mdx/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/@mdx-js/react": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-1.6.22.tgz", - "integrity": "sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - }, - "peerDependencies": { - "react": "^16.13.1 || ^17.0.0" - } - }, - "node_modules/@mdx-js/rollup": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@mdx-js/rollup/-/rollup-3.0.0.tgz", - "integrity": "sha512-ITvGiwPGEBW+D7CCnpSA9brzAosIWHAi4y+Air8wgfLnez8aWue50avHtWMfnFLCp7vt+JQ9UM8nwfuQuuydxw==", - "dependencies": { - "@mdx-js/mdx": "^3.0.0", - "@rollup/pluginutils": "^5.0.0", - "source-map": "^0.7.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - }, - "peerDependencies": { - "rollup": ">=2" - } - }, - "node_modules/@mdx-js/rollup/node_modules/@mdx-js/mdx": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.0.0.tgz", - "integrity": "sha512-Icm0TBKBLYqroYbNW3BPnzMGn+7mwpQOK310aZ7+fkCtiU3aqv2cdcX+nd0Ydo3wI5Rx8bX2Z2QmGb/XcAClCw==", + "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", "@types/estree-jsx": "^1.0.0", @@ -1605,234 +1140,50 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/@mdx-js/rollup/node_modules/@types/hast": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", - "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/@mdx-js/rollup/node_modules/@types/mdast": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz", - "integrity": "sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/@mdx-js/rollup/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, - "node_modules/@mdx-js/rollup/node_modules/bail": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", - "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/@mdx-js/rollup/node_modules/collapse-white-space": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", - "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/@mdx-js/rollup/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/@mdx-js/rollup/node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "node_modules/@mdx-js/mdx/node_modules/source-map": { + "version": "0.7.4", + "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@mdx-js/rollup/node_modules/mdast-util-to-hast": { - "version": "13.0.2", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.0.2.tgz", - "integrity": "sha512-U5I+500EOOw9e3ZrclN3Is3fRpw8c19SMyNZlZ2IS+7vLsNzb2Om11VpIVOR+/0137GhZsFEF6YiKD5+0Hr2Og==", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@ungap/structured-clone": "^1.0.0", - "devlop": "^1.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "trim-lines": "^3.0.0", - "unist-util-position": "^5.0.0", - "unist-util-visit": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "node": ">= 8" } }, - "node_modules/@mdx-js/rollup/node_modules/remark-mdx": { + "node_modules/@mdx-js/rollup": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.0.0.tgz", - "integrity": "sha512-O7yfjuC6ra3NHPbRVxfflafAj3LTwx3b73aBvkEFU5z4PsD6FD4vrqJAkE5iNGLz71GdjXfgRqm3SQ0h0VuE7g==", - "dependencies": { - "mdast-util-mdx": "^3.0.0", - "micromark-extension-mdxjs": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/@mdx-js/rollup/node_modules/remark-parse": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", - "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-from-markdown": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/@mdx-js/rollup/node_modules/remark-rehype": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.0.0.tgz", - "integrity": "sha512-vx8x2MDMcxuE4lBmQ46zYUDfcFMmvg80WYX+UNLeG6ixjdCCLcw1lrgAukwBTuOFsS78eoAedHGn9sNM0w7TPw==", + "dev": true, + "license": "MIT", "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "mdast-util-to-hast": "^13.0.0", - "unified": "^11.0.0", + "@mdx-js/mdx": "^3.0.0", + "@rollup/pluginutils": "^5.0.0", + "source-map": "^0.7.0", "vfile": "^6.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "rollup": ">=2" } }, "node_modules/@mdx-js/rollup/node_modules/source-map": { "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">= 8" } }, - "node_modules/@mdx-js/rollup/node_modules/trough": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", - "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/@mdx-js/rollup/node_modules/unified": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", - "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", - "dependencies": { - "@types/unist": "^3.0.0", - "bail": "^2.0.0", - "devlop": "^1.0.0", - "extend": "^3.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/@mdx-js/rollup/node_modules/unist-util-is": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", - "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/@mdx-js/rollup/node_modules/unist-util-position": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", - "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/@mdx-js/rollup/node_modules/unist-util-visit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", - "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/@mdx-js/rollup/node_modules/unist-util-visit-parents": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", - "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/@mdx-js/util": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/@mdx-js/util/-/util-1.6.22.tgz", - "integrity": "sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/@mui/base": { - "version": "5.0.0-beta.29", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.29.tgz", - "integrity": "sha512-OXfUssYrB6ch/xpBVHMKAjThPlI9VyGGKdvQLMXef2j39wXfcxPlUVQlwia/lmE3rxWIGvbwkZsDtNYzLMsDUg==", - "dependencies": { - "@babel/runtime": "^7.23.6", - "@floating-ui/react-dom": "^2.0.4", - "@mui/types": "^7.2.11", - "@mui/utils": "^5.15.2", + "version": "5.0.0-beta.33", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.8", + "@floating-ui/react-dom": "^2.0.6", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.6", "@popperjs/core": "^2.11.8", - "clsx": "^2.0.0", + "clsx": "^2.1.0", "prop-types": "^15.8.1" }, "engines": { @@ -1855,27 +1206,24 @@ }, "node_modules/@mui/base/node_modules/clsx": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", - "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.15.2", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.2.tgz", - "integrity": "sha512-0vk4ckS2w1F5PmkSXSd7F/QuRlNcPqWTJ8CPl+HQRLTIhJVS/VKEI+3dQufOdKfn2wS+ecnvlvXerbugs+xZ8Q==", + "version": "5.15.6", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" } }, "node_modules/@mui/icons-material": { - "version": "5.15.2", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.15.2.tgz", - "integrity": "sha512-Vs0Z6cd6ieTavMjqPvIJJfwsKaCLdRSErk5LjKdZlBqk7r2SR6roDyhVTQuZOeCzjEFj0qZ4iVPp2DJZRwuYbw==", + "version": "5.15.6", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.23.6" + "@babel/runtime": "^7.23.8" }, "engines": { "node": ">=12.0.0" @@ -1896,16 +1244,15 @@ } }, "node_modules/@mui/lab": { - "version": "5.0.0-alpha.158", - "resolved": "https://registry.npmjs.org/@mui/lab/-/lab-5.0.0-alpha.158.tgz", - "integrity": "sha512-MNn/J07GAipfElEEzDD9O7KLxz+mKgONJ+zBmlLgcCpDFsOh6nAuVQ2ONbeg1cgV/e553jXv8QHTWSRXw8KX4A==", - "dependencies": { - "@babel/runtime": "^7.23.6", - "@mui/base": "5.0.0-beta.29", - "@mui/system": "^5.15.2", - "@mui/types": "^7.2.11", - "@mui/utils": "^5.15.2", - "clsx": "^2.0.0", + "version": "5.0.0-alpha.162", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.8", + "@mui/base": "5.0.0-beta.33", + "@mui/system": "^5.15.6", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.6", + "clsx": "^2.1.0", "prop-types": "^15.8.1" }, "engines": { @@ -1918,7 +1265,7 @@ "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@mui/material": ">=5.10.11", + "@mui/material": ">=5.15.0", "@types/react": "^17.0.0 || ^18.0.0", "react": "^17.0.0 || ^18.0.0", "react-dom": "^17.0.0 || ^18.0.0" @@ -1937,25 +1284,24 @@ }, "node_modules/@mui/lab/node_modules/clsx": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", - "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/@mui/material": { - "version": "5.15.2", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.2.tgz", - "integrity": "sha512-JnoIrpNmEHG5uC1IyEdgsnDiaiuCZnUIh7f9oeAr87AvBmNiEJPbo7XrD7kBTFWwp+b97rQ12QdSs9CLhT2n/A==", - "dependencies": { - "@babel/runtime": "^7.23.6", - "@mui/base": "5.0.0-beta.29", - "@mui/core-downloads-tracker": "^5.15.2", - "@mui/system": "^5.15.2", - "@mui/types": "^7.2.11", - "@mui/utils": "^5.15.2", + "version": "5.15.6", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.6.tgz", + "integrity": "sha512-rw7bDdpi2kzfmcDN78lHp8swArJ5sBCKsn+4G3IpGfu44ycyWAWX0VdlvkjcR9Yrws2KIm7c+8niXpWHUDbWoA==", + "dependencies": { + "@babel/runtime": "^7.23.8", + "@mui/base": "5.0.0-beta.33", + "@mui/core-downloads-tracker": "^5.15.6", + "@mui/system": "^5.15.6", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.6", "@types/react-transition-group": "^4.4.10", - "clsx": "^2.0.0", + "clsx": "^2.1.0", "csstype": "^3.1.2", "prop-types": "^15.8.1", "react-is": "^18.2.0", @@ -1989,19 +1335,17 @@ }, "node_modules/@mui/material/node_modules/clsx": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", - "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/@mui/private-theming": { - "version": "5.15.2", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.2.tgz", - "integrity": "sha512-KlXx5TH1Mw9omSY+Q6rz5TA/P71meSYaAOeopiW8s6o433+fnOxS17rZbmd1RnDZGCo+j24TfCavQuCMBAZnQA==", + "version": "5.15.6", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.23.6", - "@mui/utils": "^5.15.2", + "@babel/runtime": "^7.23.8", + "@mui/utils": "^5.15.6", "prop-types": "^15.8.1" }, "engines": { @@ -2022,11 +1366,10 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.15.2", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.15.2.tgz", - "integrity": "sha512-fYEN3IZzbebeHwAmQHhxwruiOIi8W74709qXg/7tgtHV4byQSmPgnnKsZkg0hFlzjEbcJIRZyZI0qEecgpR2cg==", + "version": "5.15.6", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.23.6", + "@babel/runtime": "^7.23.8", "@emotion/cache": "^11.11.0", "csstype": "^3.1.2", "prop-types": "^15.8.1" @@ -2053,16 +1396,15 @@ } }, "node_modules/@mui/system": { - "version": "5.15.2", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.2.tgz", - "integrity": "sha512-I7CzLiHDtU/BTobJgSk+wPGGWG95K8lYfdFEnq//wOgSrLDAdOVvl2gleDxJWO+yAbGz4RKEOnR9KuD+xQZH4A==", - "dependencies": { - "@babel/runtime": "^7.23.6", - "@mui/private-theming": "^5.15.2", - "@mui/styled-engine": "^5.15.2", - "@mui/types": "^7.2.11", - "@mui/utils": "^5.15.2", - "clsx": "^2.0.0", + "version": "5.15.6", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.8", + "@mui/private-theming": "^5.15.6", + "@mui/styled-engine": "^5.15.6", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.6", + "clsx": "^2.1.0", "csstype": "^3.1.2", "prop-types": "^15.8.1" }, @@ -2093,16 +1435,14 @@ }, "node_modules/@mui/system/node_modules/clsx": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", - "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/@mui/types": { - "version": "7.2.11", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.11.tgz", - "integrity": "sha512-KWe/QTEsFFlFSH+qRYf3zoFEj3z67s+qAuSnMMg+gFwbxG7P96Hm6g300inQL1Wy///gSRb8juX7Wafvp93m3w==", + "version": "7.2.13", + "license": "MIT", "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0" }, @@ -2113,11 +1453,10 @@ } }, "node_modules/@mui/utils": { - "version": "5.15.2", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.2.tgz", - "integrity": "sha512-6dGM9/guFKBlFRHA7/mbM+E7wE7CYDy9Ny4JLtD3J+NTyhi8nd8YxlzgAgTaTVqY0BpdQ2zdfB/q6+p2EdGM0w==", + "version": "5.15.6", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.23.6", + "@babel/runtime": "^7.23.8", "@types/prop-types": "^15.7.11", "prop-types": "^15.8.1", "react-is": "^18.2.0" @@ -2141,8 +1480,7 @@ }, "node_modules/@mui/x-date-pickers": { "version": "5.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-5.0.0-beta.6.tgz", - "integrity": "sha512-8NS3s1uslmmZLl1KVCJ6eu9Wnago0EUdRb4NTCmJOwphE2w7cdI4LP+ZGRH7uWtkb6dQEmum1oumBAB3g4Ix+A==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.6", "@date-io/core": "^2.15.0", @@ -2199,9 +1537,8 @@ }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -2212,18 +1549,16 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -2232,21 +1567,18 @@ "node": ">= 8" } }, - "node_modules/@openreplay/tracker": { - "version": "3.6.6", - "resolved": "https://registry.npmjs.org/@openreplay/tracker/-/tracker-3.6.6.tgz", - "integrity": "sha512-mM1s/D+v+oyD+xlwF/GP5JsHrSXziIZvF4e85WMDa/zaboVgEg1m0VpJtCd3SiDCESaXcZA20iDXcfWPVmRPAw==", - "dependencies": { - "error-stack-parser": "^2.0.6" - }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "dev": true, + "license": "MIT", + "optional": true, "engines": { - "node": ">=14.0" + "node": ">=14" } }, "node_modules/@popperjs/core": { "version": "2.11.8", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", - "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" @@ -2254,24 +1586,20 @@ }, "node_modules/@react-dnd/asap": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-4.0.1.tgz", - "integrity": "sha512-kLy0PJDDwvwwTXxqTFNAAllPHD73AycE9ypWeln/IguoGBEbvFcPDbCV03G52bEcC5E+YgupBE0VzHGdC8SIXg==" + "license": "MIT" }, "node_modules/@react-dnd/invariant": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-2.0.0.tgz", - "integrity": "sha512-xL4RCQBCBDJ+GRwKTFhGUW8GXa4yoDfJrPbLblc3U09ciS+9ZJXJ3Qrcs/x2IODOdIE5kQxvMmE2UKyqUictUw==" + "license": "MIT" }, "node_modules/@react-dnd/shallowequal": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz", - "integrity": "sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==" + "license": "MIT" }, "node_modules/@rollup/plugin-inject": { "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@rollup/plugin-inject/-/plugin-inject-5.0.5.tgz", - "integrity": "sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==", "dev": true, + "license": "MIT", "dependencies": { "@rollup/pluginutils": "^5.0.1", "estree-walker": "^2.0.2", @@ -2289,10 +1617,15 @@ } } }, + "node_modules/@rollup/plugin-inject/node_modules/estree-walker": { + "version": "2.0.2", + "dev": true, + "license": "MIT" + }, "node_modules/@rollup/pluginutils": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", - "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", + "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", @@ -2310,524 +1643,387 @@ } } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.2.tgz", - "integrity": "sha512-RKzxFxBHq9ysZ83fn8Iduv3A283K7zPPYuhL/z9CQuyFrjwpErJx0h4aeb/bnJ+q29GRLgJpY66ceQ/Wcsn3wA==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ], - "peer": true - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.2.tgz", - "integrity": "sha512-yZ+MUbnwf3SHNWQKJyWh88ii2HbuHCFQnAYTeeO1Nb8SyEiWASEi5dQUygt3ClHWtA9My9RQAYkjvrsZ0WK8Xg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "peer": true - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.2.tgz", - "integrity": "sha512-vqJ/pAUh95FLc/G/3+xPqlSBgilPnauVf2EXOQCZzhZJCXDXt/5A8mH/OzU6iWhb3CNk5hPJrh8pqJUPldN5zw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "peer": true - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.2.tgz", - "integrity": "sha512-otPHsN5LlvedOprd3SdfrRNhOahhVBwJpepVKUN58L0RnC29vOAej1vMEaVU6DadnpjivVsNTM5eNt0CcwTahw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.2.tgz", - "integrity": "sha512-ewG5yJSp+zYKBYQLbd1CUA7b1lSfIdo9zJShNTyc2ZP1rcPrqyZcNlsHgs7v1zhgfdS+kW0p5frc0aVqhZCiYQ==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.2.tgz", - "integrity": "sha512-pL6QtV26W52aCWTG1IuFV3FMPL1m4wbsRG+qijIvgFO/VBsiXJjDPE/uiMdHBAO6YcpV4KvpKtd0v3WFbaxBtg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.2.tgz", - "integrity": "sha512-On+cc5EpOaTwPSNetHXBuqylDW+765G/oqB9xGmWU3npEhCh8xu0xqHGUA+4xwZLqBbIZNcBlKSIYfkBm6ko7g==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.2.tgz", - "integrity": "sha512-Wnx/IVMSZ31D/cO9HSsU46FjrPWHqtdF8+0eyZ1zIB5a6hXaZXghUKpRrC4D5DcRTZOjml2oBhXoqfGYyXKipw==", - "cpu": [ - "riscv64" - ], - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.2.tgz", - "integrity": "sha512-ym5x1cj4mUAMBummxxRkI4pG5Vht1QMsJexwGP8547TZ0sox9fCLDHw9KCH9c1FO5d9GopvkaJsBIOkTKxksdw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.2.tgz", - "integrity": "sha512-m0hYELHGXdYx64D6IDDg/1vOJEaiV8f1G/iO+tejvRCJNSwK4jJ15e38JQy5Q6dGkn1M/9KcyEOwqmlZ2kqaZg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.2.tgz", - "integrity": "sha512-x1CWburlbN5JjG+juenuNa4KdedBdXLjZMp56nHFSHTOsb/MI2DYiGzLtRGHNMyydPGffGId+VgjOMrcltOksA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "peer": true - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.2.tgz", - "integrity": "sha512-VVzCB5yXR1QlfsH1Xw1zdzQ4Pxuzv+CPr5qpElpKhVxlxD3CRdfubAG9mJROl6/dmj5gVYDDWk8sC+j9BI9/kQ==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "peer": true + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "2.0.2", + "dev": true, + "license": "MIT" }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.2.tgz", - "integrity": "sha512-SYRedJi+mweatroB+6TTnJYLts0L0bosg531xnQWtklOI6dezEagx4Q0qDyvRdK+qgdA3YZpjjGuPFtxBmddBA==", + "version": "4.9.6", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@sentry-internal/feedback": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-7.91.0.tgz", - "integrity": "sha512-SJKTSaz68F5YIwF79EttBm915M2LnacgZMYRnRumyTmMKnebGhYQLwWbZdpaDvOa1U18dgRajDX8Qed/8A3tXw==", + "version": "7.98.0", + "license": "MIT", "dependencies": { - "@sentry/core": "7.91.0", - "@sentry/types": "7.91.0", - "@sentry/utils": "7.91.0" + "@sentry/core": "7.98.0", + "@sentry/types": "7.98.0", + "@sentry/utils": "7.98.0" }, "engines": { "node": ">=12" } }, "node_modules/@sentry-internal/feedback/node_modules/@sentry/types": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.91.0.tgz", - "integrity": "sha512-bcQnb7J3P3equbCUc+sPuHog2Y47yGD2sCkzmnZBjvBT0Z1B4f36fI/5WjyZhTjLSiOdg3F2otwvikbMjmBDew==", + "version": "7.98.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@sentry-internal/replay-canvas": { + "version": "7.98.0", + "license": "MIT", + "dependencies": { + "@sentry/core": "7.98.0", + "@sentry/replay": "7.98.0", + "@sentry/types": "7.98.0", + "@sentry/utils": "7.98.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@sentry-internal/replay-canvas/node_modules/@sentry/types": { + "version": "7.98.0", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@sentry-internal/tracing": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.91.0.tgz", - "integrity": "sha512-JH5y6gs6BS0its7WF2DhySu7nkhPDfZcdpAXldxzIlJpqFkuwQKLU5nkYJpiIyZz1NHYYtW5aum2bV2oCOdDRA==", + "version": "7.98.0", + "license": "MIT", "dependencies": { - "@sentry/core": "7.91.0", - "@sentry/types": "7.91.0", - "@sentry/utils": "7.91.0" + "@sentry/core": "7.98.0", + "@sentry/types": "7.98.0", + "@sentry/utils": "7.98.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry-internal/tracing/node_modules/@sentry/types": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.91.0.tgz", - "integrity": "sha512-bcQnb7J3P3equbCUc+sPuHog2Y47yGD2sCkzmnZBjvBT0Z1B4f36fI/5WjyZhTjLSiOdg3F2otwvikbMjmBDew==", + "version": "7.98.0", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@sentry/browser": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.91.0.tgz", - "integrity": "sha512-lJv3x/xekzC/biiyAsVCioq2XnKNOZhI6jY3ZzLJZClYV8eKRi7D3KCsHRvMiCdGak1d/6sVp8F4NYY+YiWy1Q==", + "version": "7.98.0", + "license": "MIT", "dependencies": { - "@sentry-internal/feedback": "7.91.0", - "@sentry-internal/tracing": "7.91.0", - "@sentry/core": "7.91.0", - "@sentry/replay": "7.91.0", - "@sentry/types": "7.91.0", - "@sentry/utils": "7.91.0" + "@sentry-internal/feedback": "7.98.0", + "@sentry-internal/replay-canvas": "7.98.0", + "@sentry-internal/tracing": "7.98.0", + "@sentry/core": "7.98.0", + "@sentry/replay": "7.98.0", + "@sentry/types": "7.98.0", + "@sentry/utils": "7.98.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/browser/node_modules/@sentry/types": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.91.0.tgz", - "integrity": "sha512-bcQnb7J3P3equbCUc+sPuHog2Y47yGD2sCkzmnZBjvBT0Z1B4f36fI/5WjyZhTjLSiOdg3F2otwvikbMjmBDew==", + "version": "7.98.0", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@sentry/core": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.91.0.tgz", - "integrity": "sha512-tu+gYq4JrTdrR+YSh5IVHF0fJi/Pi9y0HZ5H9HnYy+UMcXIotxf6hIEaC6ZKGeLWkGXffz2gKpQLe/g6vy/lPA==", + "version": "7.98.0", + "license": "MIT", "dependencies": { - "@sentry/types": "7.91.0", - "@sentry/utils": "7.91.0" + "@sentry/types": "7.98.0", + "@sentry/utils": "7.98.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/core/node_modules/@sentry/types": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.91.0.tgz", - "integrity": "sha512-bcQnb7J3P3equbCUc+sPuHog2Y47yGD2sCkzmnZBjvBT0Z1B4f36fI/5WjyZhTjLSiOdg3F2otwvikbMjmBDew==", + "version": "7.98.0", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@sentry/replay": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.91.0.tgz", - "integrity": "sha512-XwbesnLLNtaVXKtDoyBB96GxJuhGi9zy3a662Ba/McmumCnkXrMQYpQPh08U7MgkTyDRgjDwm7PXDhiKpcb03g==", + "version": "7.98.0", + "license": "MIT", "dependencies": { - "@sentry-internal/tracing": "7.91.0", - "@sentry/core": "7.91.0", - "@sentry/types": "7.91.0", - "@sentry/utils": "7.91.0" + "@sentry-internal/tracing": "7.98.0", + "@sentry/core": "7.98.0", + "@sentry/types": "7.98.0", + "@sentry/utils": "7.98.0" }, "engines": { "node": ">=12" } }, "node_modules/@sentry/replay/node_modules/@sentry/types": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.91.0.tgz", - "integrity": "sha512-bcQnb7J3P3equbCUc+sPuHog2Y47yGD2sCkzmnZBjvBT0Z1B4f36fI/5WjyZhTjLSiOdg3F2otwvikbMjmBDew==", + "version": "7.98.0", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@sentry/types": { "version": "6.19.7", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.19.7.tgz", - "integrity": "sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=6" } }, "node_modules/@sentry/utils": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.91.0.tgz", - "integrity": "sha512-fvxjrEbk6T6Otu++Ax9ntlQ0sGRiwSC179w68aC3u26Wr30FAIRKqHTCCdc2jyWk7Gd9uWRT/cq+g8NG/8BfSg==", + "version": "7.98.0", + "license": "MIT", "dependencies": { - "@sentry/types": "7.91.0" + "@sentry/types": "7.98.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/utils/node_modules/@sentry/types": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.91.0.tgz", - "integrity": "sha512-bcQnb7J3P3equbCUc+sPuHog2Y47yGD2sCkzmnZBjvBT0Z1B4f36fI/5WjyZhTjLSiOdg3F2otwvikbMjmBDew==", + "version": "7.98.0", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@stomp/stompjs": { "version": "6.1.2", - "resolved": "https://registry.npmjs.org/@stomp/stompjs/-/stompjs-6.1.2.tgz", - "integrity": "sha512-FHDTrIFM5Ospi4L3Xhj6v2+NzCVAeNDcBe95YjUWhWiRMrBF6uN3I7AUOlRgT6jU/2WQvvYK8ZaIxFfxFp+uHQ==" + "license": "Apache-2.0" }, - "node_modules/@testing-library/dom": { - "version": "9.3.3", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.3.tgz", - "integrity": "sha512-fB0R+fa3AUqbLHWyxXa2kGVtf1Fe1ZZFr0Zp6AIbIAzXb2mKbEXl+PCQNUOaq5lbTab5tfctfXRNsWXxa2f7Aw==", + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "8.0.0", "dev": true, - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.1.3", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "pretty-format": "^27.0.2" - }, + "license": "MIT", "engines": { "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@testing-library/dom/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", "dev": true, - "peer": true, - "dependencies": { - "color-convert": "^2.0.1" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=14" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@testing-library/dom/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", "dev": true, - "peer": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@testing-library/dom/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "8.0.0", "dev": true, - "peer": true, - "dependencies": { - "color-name": "~1.1.4" - }, + "license": "MIT", "engines": { - "node": ">=7.0.0" + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@testing-library/dom/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "8.0.0", "dev": true, - "peer": true + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/@testing-library/dom/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "8.0.0", "dev": true, - "peer": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@testing-library/dom/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "8.1.0", "dev": true, - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@testing-library/jest-dom": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz", - "integrity": "sha512-ynmNeT7asXyH3aSVv4vvX4Rb+0qjOhdNHnO/3vuZNqPmhDpV/+rCSGwQ7bLcmU2cJ4dvoheIO85LQj0IbJHEtg==", + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "8.0.0", "dev": true, - "dependencies": { - "@adobe/css-tools": "^4.0.1", - "@babel/runtime": "^7.9.2", - "@types/testing-library__jest-dom": "^5.9.1", - "aria-query": "^5.0.0", - "chalk": "^3.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.5.6", - "lodash": "^4.17.15", - "redent": "^3.0.0" - }, + "license": "MIT", "engines": { - "node": ">=8", - "npm": ">=6", - "yarn": ">=1" + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@testing-library/jest-dom/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@svgr/babel-preset": { + "version": "8.1.0", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", + "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", + "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", + "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", + "@svgr/babel-plugin-transform-svg-component": "8.0.0" }, "engines": { - "node": ">=8" + "node": ">=14" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@testing-library/jest-dom/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "node_modules/@svgr/core": { + "version": "8.1.0", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^8.1.3", + "snake-case": "^3.0.4" }, "engines": { - "node": ">=8" + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@testing-library/jest-dom/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@testing-library/jest-dom/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/@svgr/core/node_modules/camelcase": { + "version": "6.3.0", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@testing-library/jest-dom/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "8.0.0", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@babel/types": "^7.21.3", + "entities": "^4.4.0" }, "engines": { - "node": ">=8" + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@testing-library/react": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-12.1.5.tgz", - "integrity": "sha512-OfTXCJUFgjd/digLUuPxa0+/3ZxsQmE7ub9kcbW/wi96Bh3o/p5vrETcBGfP17NWPGqeYYl5LTRpwyGoMC4ysg==", + "node_modules/@svgr/plugin-jsx": { + "version": "8.1.0", "dev": true, + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^8.0.0", - "@types/react-dom": "<18.0.0" + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "@svgr/hast-util-to-babel-ast": "8.0.0", + "svg-parser": "^2.0.4" }, "engines": { - "node": ">=12" + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" }, "peerDependencies": { - "react": "<18.0.0", - "react-dom": "<18.0.0" + "@svgr/core": "*" } }, - "node_modules/@testing-library/react/node_modules/@testing-library/dom": { - "version": "8.20.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.1.tgz", - "integrity": "sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g==", + "node_modules/@testing-library/dom": { + "version": "9.3.4", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -2839,84 +2035,81 @@ "pretty-format": "^27.0.2" }, "engines": { - "node": ">=12" + "node": ">=14" } }, - "node_modules/@testing-library/react/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@testing-library/jest-dom": { + "version": "5.17.0", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "@adobe/css-tools": "^4.0.1", + "@babel/runtime": "^7.9.2", + "@types/testing-library__jest-dom": "^5.9.1", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.5.6", + "lodash": "^4.17.15", + "redent": "^3.0.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=8", + "npm": ">=6", + "yarn": ">=1" } }, - "node_modules/@testing-library/react/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@testing-library/jest-dom/node_modules/chalk": { + "version": "3.0.0", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=8" } }, - "node_modules/@testing-library/react/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@testing-library/react": { + "version": "12.1.5", "dev": true, + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "@babel/runtime": "^7.12.5", + "@testing-library/dom": "^8.0.0", + "@types/react-dom": "<18.0.0" }, "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@testing-library/react/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@testing-library/react/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" + "node": ">=12" + }, + "peerDependencies": { + "react": "<18.0.0", + "react-dom": "<18.0.0" } }, - "node_modules/@testing-library/react/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@testing-library/react/node_modules/@testing-library/dom": { + "version": "8.20.1", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.1.3", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" }, "engines": { - "node": ">=8" + "node": ">=12" } }, "node_modules/@testing-library/user-event": { "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.5.0.tgz", - "integrity": "sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.5" }, @@ -2930,31 +2123,29 @@ }, "node_modules/@tginternal/language-util": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@tginternal/language-util/-/language-util-1.0.6.tgz", - "integrity": "sha512-PHe6+0zbeFCCAfOJsfGfk1mWReQB2GvO5vEl674dAI0Wi05e+ufJN8HeMzGu2onEFqp+yQrHbJp9JjExEQie6g==", "dev": true, + "license": "MIT", "dependencies": { "@formatjs/intl-getcanonicallocales": "^1.7.0", "latinize": "^0.5.0" } }, "node_modules/@tolgee/cli": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@tolgee/cli/-/cli-1.0.1.tgz", - "integrity": "sha512-Iq3UilrQTTuWqLoExnP8Fy3BWm5O9zE/DQTNTSfrVkukkd1r6z9w8GA9RP25PP9AWQIyDcLQ4Sn2fhddZOrwMg==", + "version": "1.3.2", "dev": true, + "license": "MIT", "dependencies": { "ansi-colors": "^4.1.3", "base32-decode": "^1.0.0", - "commander": "^10.0.0", - "cosmiconfig": "^8.0.0", + "commander": "^11.0.0", + "cosmiconfig": "^8.2.0", "form-data": "^4.0.0", - "glob": "^8.1.0", + "glob": "^10.3.3", "json5": "^2.2.3", - "undici": "^5.15.0", + "undici": "^5.22.1", "vscode-oniguruma": "^1.7.0", - "vscode-textmate": "^8.0.0", - "xstate": "^4.35.2", + "vscode-textmate": "^9.0.0", + "xstate": "^4.38.1", "yauzl": "^2.10.0" }, "bin": { @@ -2964,97 +2155,47 @@ "node": ">= 18" } }, - "node_modules/@tolgee/cli/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/@tolgee/cli/node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dev": true, - "dependencies": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@tolgee/cli/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/@tolgee/core": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/@tolgee/core/-/core-5.19.0.tgz", - "integrity": "sha512-5zOkxjtxUBEC8xTWtYU5r6bvwHK80s95zH4Y4uLkTcIYTRvn4kY7Z5/Hg5/hyIApA6P8taOrNy/m5favxCmREQ==" + "version": "5.19.3", + "license": "MIT" }, "node_modules/@tolgee/format-icu": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/@tolgee/format-icu/-/format-icu-5.19.0.tgz", - "integrity": "sha512-hV8MJEFrN90nAWNWHsz7RZy7S/23cIuETZ3exKGlu7m397BTtqT/52eE3bh4lcAeKwvhfF+v/hWT+vZrkNxmwA==" + "version": "5.19.3", + "license": "MIT" }, "node_modules/@tolgee/react": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/@tolgee/react/-/react-5.19.0.tgz", - "integrity": "sha512-FYQyymza7NQ/aqPZqpm/7ErHI7T8QeptbjKDSekomaN6nxifumSzYpuvjhBX+y2o/z1HGdqWZR9sc1IJU0VAwQ==", + "version": "5.19.3", + "license": "MIT", "dependencies": { - "@tolgee/web": "5.19.0" + "@tolgee/web": "5.19.3" }, "peerDependencies": { "react": "^16.14.0 || ^17.0.1 || ^18.1.0" } }, "node_modules/@tolgee/web": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/@tolgee/web/-/web-5.19.0.tgz", - "integrity": "sha512-a57howuvHz6KGDg8wu6K1KxuBlTUD/AV0+1UKj+2xiFECNQSqwP8/bGO+9Hb9xkNqVxx+l1R13xK9XSZMGXNhw==", + "version": "5.19.3", + "license": "BSD-3-Clause", "dependencies": { - "@tolgee/core": "5.19.0" + "@tolgee/core": "5.19.3" } }, "node_modules/@types/acorn": { "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", - "integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==", + "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "*" } }, "node_modules/@types/aria-query": { "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", - "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/babel__core": { "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "license": "MIT", "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", @@ -3065,16 +2206,14 @@ }, "node_modules/@types/babel__generator": { "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__template": { "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" @@ -3082,105 +2221,104 @@ }, "node_modules/@types/babel__traverse": { "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", - "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", + "license": "MIT", "dependencies": { "@babel/types": "^7.20.7" } }, "node_modules/@types/codemirror": { "version": "5.60.15", - "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.15.tgz", - "integrity": "sha512-dTOvwEQ+ouKJ/rE9LT1Ue2hmP6H1mZv5+CCnNWu2qtiOe2LQa9lCprEY20HxiDmV/Bxh+dXjywmy5aKvoGjULA==", "dev": true, + "license": "MIT", "dependencies": { "@types/tern": "*" } }, + "node_modules/@types/d3-array": { + "version": "3.2.1", + "license": "MIT" + }, "node_modules/@types/d3-color": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-2.0.6.tgz", - "integrity": "sha512-tbaFGDmJWHqnenvk3QGSvD3RVwr631BjKRD7Sc7VLRgrdX5mk5hTyoeBL6rXZaeoXzmZwIl1D2HPogEdt1rHBg==" + "version": "3.1.3", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "license": "MIT" }, "node_modules/@types/d3-interpolate": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-2.0.5.tgz", - "integrity": "sha512-UINE41RDaUMbulp+bxQMDnhOi51rh5lA2dG+dWZU0UY/IwQiG/u2x8TfnWYU9+xwGdXsJoAvrBYUEQl0r91atg==", + "version": "3.0.4", + "license": "MIT", "dependencies": { - "@types/d3-color": "^2" + "@types/d3-color": "*" } }, "node_modules/@types/d3-path": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-2.0.4.tgz", - "integrity": "sha512-jjZVLBjEX4q6xneKMmv62UocaFJFOTQSb/1aTzs3m3ICTOFoVaqGBHpNLm/4dVi0/FTltfBKgmOK1ECj3/gGjA==" + "version": "3.0.2", + "license": "MIT" }, "node_modules/@types/d3-scale": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-3.3.5.tgz", - "integrity": "sha512-YOpKj0kIEusRf7ofeJcSZQsvKbnTwpe1DUF+P2qsotqG53kEsjm7EzzliqQxMkAWdkZcHrg5rRhB4JiDOQPX+A==", + "version": "4.0.8", + "license": "MIT", "dependencies": { - "@types/d3-time": "^2" + "@types/d3-time": "*" } }, "node_modules/@types/d3-shape": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-2.1.7.tgz", - "integrity": "sha512-HedHlfGHdwzKqX9+PiQVXZrdmGlwo7naoefJP7kCNk4Y7qcpQt1tUaoRa6qn0kbTdlaIHGO7111qLtb/6J8uuw==", + "version": "3.1.6", + "license": "MIT", "dependencies": { - "@types/d3-path": "^2" + "@types/d3-path": "*" } }, "node_modules/@types/d3-time": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-2.1.4.tgz", - "integrity": "sha512-BTfLsxTeo7yFxI/haOOf1ZwJ6xKgQLT9dCp+EcmQv87Gox6X+oKl4mLKfO6fnWm3P22+A6DknMNEZany8ql2Rw==" + "version": "3.0.3", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "license": "MIT" }, "node_modules/@types/debug": { "version": "4.1.12", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", - "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", "dependencies": { "@types/ms": "*" } }, "node_modules/@types/diff": { "version": "5.0.9", - "resolved": "https://registry.npmjs.org/@types/diff/-/diff-5.0.9.tgz", - "integrity": "sha512-RWVEhh/zGXpAVF/ZChwNnv7r4rvqzJ7lYNSmZSVTxjV0PBLf6Qu7RNg+SUtkpzxmiNkjCx0Xn2tPp7FIkshJwQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/estree": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" + "license": "MIT" }, "node_modules/@types/estree-jsx": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.3.tgz", - "integrity": "sha512-pvQ+TKeRHeiUGRhvYwRrQ/ISnohKkSJR14fT2yqyZ4e9K5vqc7hrtY2Y1Dw0ZwAzQ6DQsxsaCUuSIIi8v0Cq6w==", + "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "*" } }, "node_modules/@types/hast": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.9.tgz", - "integrity": "sha512-pTHyNlaMD/oKJmS+ZZUyFUcsZeBZpC0lmGquw98CqRVNgAdJZJeD7GoeLiT6Xbx5rU9VCjSt0RwEvDgzh4obFw==", + "version": "3.0.3", + "dev": true, + "license": "MIT", "dependencies": { - "@types/unist": "^2" + "@types/unist": "*" } }, "node_modules/@types/history": { "version": "4.7.11", - "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", - "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/hoist-non-react-statics": { "version": "3.3.5", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", - "integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==", + "license": "MIT", "dependencies": { "@types/react": "*", "hoist-non-react-statics": "^3.3.0" @@ -3188,76 +2326,38 @@ }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "dev": true, + "license": "MIT", "dependencies": { "@types/istanbul-lib-coverage": "*" } }, "node_modules/@types/istanbul-reports": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/istanbul-lib-report": "*" } }, "node_modules/@types/jest": { "version": "26.0.24", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.24.tgz", - "integrity": "sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w==", "dev": true, + "license": "MIT", "dependencies": { "jest-diff": "^26.0.0", "pretty-format": "^26.0.0" } }, - "node_modules/@types/jest/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@types/jest/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@types/jest/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/@types/jest/node_modules/pretty-format": { "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^26.6.2", "ansi-regex": "^5.0.0", @@ -3270,85 +2370,72 @@ }, "node_modules/@types/jest/node_modules/react-is": { "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/json-schema": { "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" + "license": "MIT" }, "node_modules/@types/json5": { "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/lodash": { "version": "4.14.202", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", - "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==" + "license": "MIT" }, "node_modules/@types/mdast": { - "version": "3.0.15", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz", - "integrity": "sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==", + "version": "4.0.3", + "dev": true, + "license": "MIT", "dependencies": { - "@types/unist": "^2" + "@types/unist": "*" } }, "node_modules/@types/mdx": { "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.10.tgz", - "integrity": "sha512-Rllzc5KHk0Al5/WANwgSPl1/CwjqCy+AZrGd78zuK+jO9aDM6ffblZ+zIjgPNAaEBmlO0RYDvLNh7wD0zKVgEg==" + "dev": true, + "license": "MIT" }, "node_modules/@types/minimist": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/ms": { "version": "0.7.34", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", - "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" + "license": "MIT" }, "node_modules/@types/node": { - "version": "18.19.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.4.tgz", - "integrity": "sha512-xNzlUhzoHotIsnFoXmJB+yWmBvFZgKCI9TtPIEdYIMM1KWfwuY8zh7wvc1u1OAXlC7dlf6mZVx/s+Y5KfFz19A==", + "version": "18.19.10", "devOptional": true, + "license": "MIT", "dependencies": { "undici-types": "~5.26.4" } }, "node_modules/@types/normalize-package-data": { "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", - "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/parse-json": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + "license": "MIT" }, - "node_modules/@types/parse5": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz", - "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==", - "dev": true + "node_modules/@types/prismjs": { + "version": "1.26.3", + "license": "MIT" }, "node_modules/@types/prop-types": { "version": "15.7.11", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", - "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" + "license": "MIT" }, "node_modules/@types/react": { - "version": "17.0.74", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.74.tgz", - "integrity": "sha512-nBtFGaeTMzpiL/p73xbmCi00SiCQZDTJUk9ZuHOLtil3nI+y7l269LHkHIAYpav99ZwGnPJzuJsJpfLXjiQ52g==", + "version": "17.0.75", + "license": "MIT", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -3357,26 +2444,23 @@ }, "node_modules/@types/react-dom": { "version": "17.0.25", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.25.tgz", - "integrity": "sha512-urx7A7UxkZQmThYA4So0NelOVjx3V4rNFVJwp0WZlbIK5eM4rNJDiN3R/E9ix0MBh6kAEojk/9YL+Te6D9zHNA==", "dev": true, + "license": "MIT", "dependencies": { "@types/react": "^17" } }, "node_modules/@types/react-list": { "version": "0.8.11", - "resolved": "https://registry.npmjs.org/@types/react-list/-/react-list-0.8.11.tgz", - "integrity": "sha512-mUfWOutmUDUicT9T1MySV6jLtbFnslyZCvXhIWGnAIah6GZsSF4yUXnX8UfdLP/PptCRPVpjxO/ksneU7j1y+A==", "dev": true, + "license": "MIT", "dependencies": { "@types/react": "*" } }, "node_modules/@types/react-redux": { "version": "7.1.33", - "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.33.tgz", - "integrity": "sha512-NF8m5AjWCkert+fosDsN3hAlHzpjSiXlVy9EgQEmLoBhaNXbmyeGs/aj5dQzKuF+/q+S7JQagorGDW8pJ28Hmg==", + "license": "MIT", "dependencies": { "@types/hoist-non-react-statics": "^3.3.0", "@types/react": "*", @@ -3386,9 +2470,8 @@ }, "node_modules/@types/react-router": { "version": "5.1.20", - "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", - "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", "dev": true, + "license": "MIT", "dependencies": { "@types/history": "^4.7.11", "@types/react": "*" @@ -3396,9 +2479,8 @@ }, "node_modules/@types/react-router-dom": { "version": "5.3.3", - "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", - "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", "dev": true, + "license": "MIT", "dependencies": { "@types/history": "^4.7.11", "@types/react": "*", @@ -3407,89 +2489,74 @@ }, "node_modules/@types/react-transition-group": { "version": "4.4.10", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", - "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", + "license": "MIT", "dependencies": { "@types/react": "*" } }, - "node_modules/@types/resize-observer-browser": { - "version": "0.1.11", - "resolved": "https://registry.npmjs.org/@types/resize-observer-browser/-/resize-observer-browser-0.1.11.tgz", - "integrity": "sha512-cNw5iH8JkMkb3QkCoe7DaZiawbDQEUX8t7iuQaRTyLOyQCR2h+ibBD4GJt7p5yhUHrlOeL7ZtbxNHeipqNsBzQ==" - }, "node_modules/@types/scheduler": { "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", - "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==" + "license": "MIT" }, "node_modules/@types/semver": { "version": "7.5.6", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", - "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/tern": { "version": "0.23.9", - "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.9.tgz", - "integrity": "sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==", "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "*" } }, "node_modules/@types/testing-library__jest-dom": { "version": "5.14.9", - "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.9.tgz", - "integrity": "sha512-FSYhIjFlfOpGSRyVoMBMuS3ws5ehFQODymf3vlI7U1K8c7PHwWwFY7VREfmsuzHSOnoKs/9/Y983ayOs7eRzqw==", "dev": true, + "license": "MIT", "dependencies": { "@types/jest": "*" } }, "node_modules/@types/unist": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", - "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==" + "version": "3.0.2", + "dev": true, + "license": "MIT" }, "node_modules/@types/yargs": { "version": "15.0.19", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.19.tgz", - "integrity": "sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==", "dev": true, + "license": "MIT", "dependencies": { "@types/yargs-parser": "*" } }, "node_modules/@types/yargs-parser": { "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/yup": { "version": "0.29.14", - "resolved": "https://registry.npmjs.org/@types/yup/-/yup-0.29.14.tgz", - "integrity": "sha512-Ynb/CjHhE/Xp/4bhHmQC4U1Ox+I2OpfRYF3dnNgQqn1cHa6LK3H1wJMNPT02tSVZA6FYuXE2ITORfbnb6zBCSA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/zxcvbn": { "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@types/zxcvbn/-/zxcvbn-4.4.4.tgz", - "integrity": "sha512-Tuk4q7q0DnpzyJDI4aMeghGuFu2iS1QAdKpabn8JfbtfGmVDUgvZv1I7mEjP61Bvnp3ljKCC8BE6YYSTNxmvRQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.17.0.tgz", - "integrity": "sha512-Vih/4xLXmY7V490dGwBQJTpIZxH4ZFH6eCVmQ4RFkB+wmaCTDAx4dtgoWwMNGKLkqRY1L6rPqzEbjorRnDo4rQ==", + "version": "6.19.1", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.17.0", - "@typescript-eslint/type-utils": "6.17.0", - "@typescript-eslint/utils": "6.17.0", - "@typescript-eslint/visitor-keys": "6.17.0", + "@typescript-eslint/scope-manager": "6.19.1", + "@typescript-eslint/type-utils": "6.19.1", + "@typescript-eslint/utils": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -3514,75 +2581,40 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/@typescript-eslint/parser": { + "version": "6.19.1", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "yallist": "^4.0.0" + "@typescript-eslint/scope-manager": "6.19.1", + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/typescript-estree": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1", + "debug": "^4.3.4" }, "engines": { - "node": ">=10" + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.19.1", "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@typescript-eslint/parser": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.17.0.tgz", - "integrity": "sha512-C4bBaX2orvhK+LlwrY8oWGmSl4WolCfYm513gEccdWZj0CwGadbIADb0FtVEcI+WzUyjyoBj2JRP8g25E6IB8A==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "6.17.0", - "@typescript-eslint/types": "6.17.0", - "@typescript-eslint/typescript-estree": "6.17.0", - "@typescript-eslint/visitor-keys": "6.17.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.17.0.tgz", - "integrity": "sha512-RX7a8lwgOi7am0k17NUO0+ZmMOX4PpjLtLRgLmT1d3lBYdWH4ssBUbwdmc5pdRX8rXon8v9x8vaoOSpkHfcXGA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.17.0", - "@typescript-eslint/visitor-keys": "6.17.0" + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -3593,13 +2625,12 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.17.0.tgz", - "integrity": "sha512-hDXcWmnbtn4P2B37ka3nil3yi3VCQO2QEB9gBiHJmQp5wmyQWqnjA85+ZcE8c4FqnaB6lBwMrPkgd4aBYz3iNg==", + "version": "6.19.1", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "6.17.0", - "@typescript-eslint/utils": "6.17.0", + "@typescript-eslint/typescript-estree": "6.19.1", + "@typescript-eslint/utils": "6.19.1", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -3620,10 +2651,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.17.0.tgz", - "integrity": "sha512-qRKs9tvc3a4RBcL/9PXtKSehI/q8wuU9xYJxe97WFxnzH8NWWtcW3ffNS+EWg8uPvIerhjsEZ+rHtDqOCiH57A==", + "version": "6.19.1", "dev": true, + "license": "MIT", "engines": { "node": "^16.0.0 || >=18.0.0" }, @@ -3633,13 +2663,12 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.17.0.tgz", - "integrity": "sha512-gVQe+SLdNPfjlJn5VNGhlOhrXz4cajwFd5kAgWtZ9dCZf4XJf8xmgCTLIqec7aha3JwgLI2CK6GY1043FRxZwg==", + "version": "6.19.1", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "6.17.0", - "@typescript-eslint/visitor-keys": "6.17.0", + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -3660,75 +2689,17 @@ } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@typescript-eslint/utils": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.17.0.tgz", - "integrity": "sha512-LofsSPjN/ITNkzV47hxas2JCsNCEnGhVvocfyOcLzT9c/tSZE7SfhS/iWtzP1lKNOEfLhRTZz6xqI8N2RzweSQ==", + "version": "6.19.1", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.17.0", - "@typescript-eslint/types": "6.17.0", - "@typescript-eslint/typescript-estree": "6.17.0", + "@typescript-eslint/scope-manager": "6.19.1", + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/typescript-estree": "6.19.1", "semver": "^7.5.4" }, "engines": { @@ -3742,46 +2713,12 @@ "eslint": "^7.0.0 || ^8.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.17.0.tgz", - "integrity": "sha512-H6VwB/k3IuIeQOyYczyyKN8wH6ed8EwliaYHLxOIhyF0dYEIsN8+Bk3GE19qafeMKyZJJHP8+O1HiFhFLUNKSg==", + "version": "6.19.1", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "6.17.0", + "@typescript-eslint/types": "6.19.1", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -3794,13 +2731,12 @@ }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + "dev": true, + "license": "ISC" }, "node_modules/@vitejs/plugin-react": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.1.tgz", - "integrity": "sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==", + "license": "MIT", "dependencies": { "@babel/core": "^7.23.5", "@babel/plugin-transform-react-jsx-self": "^7.23.3", @@ -3817,8 +2753,8 @@ }, "node_modules/acorn": { "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -3828,17 +2764,16 @@ }, "node_modules/acorn-jsx": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "node_modules/ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -3852,56 +2787,63 @@ }, "node_modules/ansi-colors": { "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/ansi-regex": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.3.0", + "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/anymatch": { + "version": "3.1.3", "dev": true, + "license": "ISC", "dependencies": { - "sprintf-js": "~1.0.2" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" } }, + "node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, "node_modules/aria-query": { "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "deep-equal": "^2.0.5" } }, "node_modules/array-buffer-byte-length": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "is-array-buffer": "^3.0.1" @@ -3912,9 +2854,8 @@ }, "node_modules/array-includes": { "version": "3.1.7", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", - "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -3931,18 +2872,16 @@ }, "node_modules/array-union": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/array.prototype.flat": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -3958,9 +2897,8 @@ }, "node_modules/array.prototype.flatmap": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -3976,9 +2914,8 @@ }, "node_modules/array.prototype.tosorted": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.2.tgz", - "integrity": "sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -3989,9 +2926,8 @@ }, "node_modules/arraybuffer.prototype.slice": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", - "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", "dev": true, + "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.0", "call-bind": "^1.0.2", @@ -4010,18 +2946,16 @@ }, "node_modules/arrify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/asn1.js": { "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", "dev": true, + "license": "MIT", "dependencies": { "bn.js": "^4.0.0", "inherits": "^2.0.1", @@ -4031,15 +2965,13 @@ }, "node_modules/asn1.js/node_modules/bn.js": { "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/assert": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", - "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "is-nan": "^1.3.2", @@ -4050,41 +2982,37 @@ }, "node_modules/astral-regex": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/astring": { "version": "1.8.6", - "resolved": "https://registry.npmjs.org/astring/-/astring-1.8.6.tgz", - "integrity": "sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==", + "dev": true, + "license": "MIT", "bin": { "astring": "bin/astring" } }, "node_modules/asynciterator.prototype": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz", - "integrity": "sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==", "dev": true, + "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" } }, "node_modules/asynckit": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/available-typed-arrays": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -4092,52 +3020,9 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/babel-plugin-apply-mdx-type-prop": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/babel-plugin-apply-mdx-type-prop/-/babel-plugin-apply-mdx-type-prop-1.6.22.tgz", - "integrity": "sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "7.10.4", - "@mdx-js/util": "1.6.22" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - }, - "peerDependencies": { - "@babel/core": "^7.11.6" - } - }, - "node_modules/babel-plugin-apply-mdx-type-prop/node_modules/@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", - "dev": true - }, - "node_modules/babel-plugin-extract-import-names": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.6.22.tgz", - "integrity": "sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "7.10.4" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/babel-plugin-extract-import-names/node_modules/@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", - "dev": true - }, "node_modules/babel-plugin-macros": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", - "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", @@ -4148,11 +3033,23 @@ "npm": ">=6" } }, + "node_modules/babel-plugin-macros/node_modules/cosmiconfig": { + "version": "7.1.0", + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/bail": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", - "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==", - "dev": true, + "version": "2.0.2", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -4160,19 +3057,15 @@ }, "node_modules/balanced-match": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "license": "MIT" }, "node_modules/base32-decode": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/base32-decode/-/base32-decode-1.0.0.tgz", - "integrity": "sha512-KNWUX/R7wKenwE/G/qFMzGScOgVntOmbE27vvc6GrniDGYb6a5+qWcuoXl8WIOQL7q0TpK7nZDm1Y04Yi3Yn5g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "dev": true, "funding": [ { @@ -4187,44 +3080,51 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/big-integer": { "version": "1.6.52", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", - "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", + "license": "Unlicense", "engines": { "node": ">=0.6" } }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "node_modules/binary-extensions": { + "version": "2.2.0", "dev": true, + "license": "MIT", "engines": { - "node": "*" + "node": ">=8" } }, "node_modules/bn.js": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "dev": true, + "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" } }, "node_modules/broadcast-channel": { "version": "3.7.0", - "resolved": "https://registry.npmjs.org/broadcast-channel/-/broadcast-channel-3.7.0.tgz", - "integrity": "sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.7.2", "detect-node": "^2.1.0", @@ -4238,24 +3138,21 @@ }, "node_modules/brorand": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/browser-resolve": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", - "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==", "dev": true, + "license": "MIT", "dependencies": { "resolve": "^1.17.0" } }, "node_modules/browserify-aes": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, + "license": "MIT", "dependencies": { "buffer-xor": "^1.0.3", "cipher-base": "^1.0.0", @@ -4267,9 +3164,8 @@ }, "node_modules/browserify-cipher": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "dev": true, + "license": "MIT", "dependencies": { "browserify-aes": "^1.0.4", "browserify-des": "^1.0.0", @@ -4278,9 +3174,8 @@ }, "node_modules/browserify-des": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "dev": true, + "license": "MIT", "dependencies": { "cipher-base": "^1.0.1", "des.js": "^1.0.0", @@ -4290,9 +3185,8 @@ }, "node_modules/browserify-rsa": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", - "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", "dev": true, + "license": "MIT", "dependencies": { "bn.js": "^5.0.0", "randombytes": "^2.0.1" @@ -4300,9 +3194,8 @@ }, "node_modules/browserify-sign": { "version": "4.2.2", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.2.tgz", - "integrity": "sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==", "dev": true, + "license": "ISC", "dependencies": { "bn.js": "^5.2.1", "browserify-rsa": "^4.1.0", @@ -4318,53 +3211,16 @@ "node": ">= 4" } }, - "node_modules/browserify-sign/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/browserify-sign/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/browserify-zlib": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "dev": true, + "license": "MIT", "dependencies": { "pako": "~1.0.5" } }, "node_modules/browserslist": { - "version": "4.22.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", - "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "version": "4.22.3", "funding": [ { "type": "opencollective", @@ -4379,9 +3235,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001565", - "electron-to-chromium": "^1.4.601", + "caniuse-lite": "^1.0.30001580", + "electron-to-chromium": "^1.4.648", "node-releases": "^2.0.14", "update-browserslist-db": "^1.0.13" }, @@ -4394,8 +3251,6 @@ }, "node_modules/buffer": { "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "dev": true, "funding": [ { @@ -4411,6 +3266,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -4418,37 +3274,26 @@ }, "node_modules/buffer-crc32": { "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true, + "license": "MIT", "engines": { "node": "*" } }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "optional": true, - "peer": true - }, "node_modules/buffer-xor": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/builtin-status-codes": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/call-bind": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", "dev": true, + "license": "MIT", "dependencies": { "function-bind": "^1.1.2", "get-intrinsic": "^1.2.1", @@ -4460,35 +3305,23 @@ }, "node_modules/callsites": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/camelcase": { "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, "node_modules/camelcase-keys": { "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", "dev": true, + "license": "MIT", "dependencies": { "camelcase": "^5.3.1", "map-obj": "^4.0.0", @@ -4502,9 +3335,7 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001572", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001572.tgz", - "integrity": "sha512-1Pbh5FLmn5y4+QhNyJE9j3/7dK44dGB83/ZMjv/qJk86TvDbjk0LosiZo0i0WB0Vx607qMX9jYrn1VLHCkN4rw==", + "version": "1.0.30001581", "funding": [ { "type": "opencollective", @@ -4518,44 +3349,36 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/ccount": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz", - "integrity": "sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==", + "version": "2.0.1", "dev": true, + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "4.1.2", + "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=4" - } - }, - "node_modules/chalk/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/character-entities": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", - "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", - "dev": true, + "version": "2.0.2", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -4563,89 +3386,106 @@ }, "node_modules/character-entities-html4": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", - "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "dev": true, + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, "node_modules/character-entities-legacy": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", - "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "version": "3.0.0", "dev": true, + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, "node_modules/character-reference-invalid": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", - "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "version": "2.0.1", "dev": true, + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/chokidar": { + "version": "3.5.3", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/cipher-base": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" } }, - "node_modules/classnames": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", - "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" - }, "node_modules/clsx": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", - "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/codemirror": { "version": "5.65.16", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.16.tgz", - "integrity": "sha512-br21LjYmSlVL0vFCPWPfhzUCT34FM/pAdK7rRIZwa0rrtrIdotvP4Oh4GUHsu2E3IrQMCfRkL/fN3ytMNxVQvg==" + "license": "MIT" }, "node_modules/collapse-white-space": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz", - "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==", + "version": "2.1.0", "dev": true, + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.0.1", + "dev": true, + "license": "MIT", "dependencies": { - "color-name": "1.1.3" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "version": "1.1.4", + "dev": true, + "license": "MIT" }, "node_modules/combined-stream": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, + "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -4654,74 +3494,74 @@ } }, "node_modules/comma-separated-tokens": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", - "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", - "dev": true, + "version": "2.0.3", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, "node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "version": "11.1.0", "dev": true, + "license": "MIT", "engines": { - "node": ">=14" + "node": ">=16" } }, "node_modules/concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "license": "MIT" }, "node_modules/console-browserify": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", - "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", "dev": true }, "node_modules/constants-browserify": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + "version": "1.9.0", + "license": "MIT" }, "node_modules/copy-to-clipboard": { "version": "3.3.3", - "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", - "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", + "license": "MIT", "dependencies": { "toggle-selection": "^1.0.6" } }, "node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "version": "8.3.6", + "dev": true, + "license": "MIT", "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/create-ecdh": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", "dev": true, + "license": "MIT", "dependencies": { "bn.js": "^4.1.0", "elliptic": "^6.5.3" @@ -4729,15 +3569,13 @@ }, "node_modules/create-ecdh/node_modules/bn.js": { "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/create-hash": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, + "license": "MIT", "dependencies": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -4748,9 +3586,8 @@ }, "node_modules/create-hmac": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, + "license": "MIT", "dependencies": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", @@ -4762,20 +3599,17 @@ }, "node_modules/create-require": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cropperjs": { "version": "1.6.1", - "resolved": "https://registry.npmjs.org/cropperjs/-/cropperjs-1.6.1.tgz", - "integrity": "sha512-F4wsi+XkDHCOMrHMYjrTEE4QBOrsHHN5/2VsVAaRq8P7E5z7xQpT75S+f/9WikmBEailas3+yo+6zPIomW+NOA==" + "license": "MIT" }, "node_modules/cross-spawn": { "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -4787,9 +3621,8 @@ }, "node_modules/crypto-browserify": { "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", "dev": true, + "license": "MIT", "dependencies": { "browserify-cipher": "^1.0.0", "browserify-sign": "^4.0.0", @@ -4807,101 +3640,117 @@ "node": "*" } }, - "node_modules/css-unit-converter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz", - "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==" - }, "node_modules/css.escape": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/csstype": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + "license": "MIT" }, "node_modules/d3-array": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", - "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "version": "3.2.4", + "license": "ISC", "dependencies": { - "internmap": "^1.0.0" + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" } }, "node_modules/d3-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz", - "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==" + "version": "3.1.0", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } }, "node_modules/d3-format": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz", - "integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA==" + "version": "3.1.0", + "license": "ISC", + "engines": { + "node": ">=12" + } }, "node_modules/d3-interpolate": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz", - "integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==", + "version": "3.0.1", + "license": "ISC", "dependencies": { - "d3-color": "1 - 2" + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" } }, "node_modules/d3-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-2.0.0.tgz", - "integrity": "sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA==" + "version": "3.1.0", + "license": "ISC", + "engines": { + "node": ">=12" + } }, "node_modules/d3-scale": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.3.0.tgz", - "integrity": "sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==", + "version": "4.0.2", + "license": "ISC", "dependencies": { - "d3-array": "^2.3.0", - "d3-format": "1 - 2", - "d3-interpolate": "1.2.0 - 2", - "d3-time": "^2.1.1", - "d3-time-format": "2 - 3" + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" } }, "node_modules/d3-shape": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-2.1.0.tgz", - "integrity": "sha512-PnjUqfM2PpskbSLTJvAzp2Wv4CZsnAgTfcVRTwW03QR3MkXF8Uo7B1y/lWkAsmbKwuecto++4NlsYcvYpXpTHA==", + "version": "3.2.0", + "license": "ISC", "dependencies": { - "d3-path": "1 - 2" + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" } }, "node_modules/d3-time": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz", - "integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==", + "version": "3.1.0", + "license": "ISC", "dependencies": { - "d3-array": "2" + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" } }, "node_modules/d3-time-format": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz", - "integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==", + "version": "4.1.0", + "license": "ISC", "dependencies": { - "d3-time": "1 - 2" + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" } }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "node_modules/d3-timer": { + "version": "3.0.1", + "license": "ISC", "engines": { - "node": ">= 12" + "node": ">=12" } }, "node_modules/date-fns": { "version": "2.29.2", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.2.tgz", - "integrity": "sha512-0VNbwmWJDS/G3ySwFSJA3ayhbURMTJLtwM2DTxf9CWondCnh6DTNlO9JgRSq6ibf4eD0lfMJNBxUdEAHHix+bA==", + "license": "MIT", "engines": { "node": ">=0.11" }, @@ -4912,8 +3761,7 @@ }, "node_modules/debug": { "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -4928,18 +3776,16 @@ }, "node_modules/decamelize": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/decamelize-keys": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", - "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", "dev": true, + "license": "MIT", "dependencies": { "decamelize": "^1.1.0", "map-obj": "^1.0.0" @@ -4953,22 +3799,19 @@ }, "node_modules/decamelize-keys/node_modules/map-obj": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/decimal.js-light": { "version": "2.5.1", - "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", - "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==" + "license": "MIT" }, "node_modules/decode-named-character-reference": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", - "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "license": "MIT", "dependencies": { "character-entities": "^2.0.0" }, @@ -4977,20 +3820,10 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/decode-named-character-reference/node_modules/character-entities": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", - "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/deep-equal": { "version": "2.2.3", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", - "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", "dev": true, + "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.0", "call-bind": "^1.0.5", @@ -5020,14 +3853,12 @@ }, "node_modules/deep-is": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/deep-rename-keys": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/deep-rename-keys/-/deep-rename-keys-0.2.1.tgz", - "integrity": "sha512-RHd9ABw4Fvk+gYDWqwOftG849x0bYOySl/RgX0tLI9i27ZIeSO91mLZJEp7oPHOMFqHvpgu21YptmDt0FYD/0A==", + "license": "MIT", "dependencies": { "kind-of": "^3.0.2", "rename-keys": "^1.1.2" @@ -5036,19 +3867,27 @@ "node": ">=0.10.0" } }, + "node_modules/deep-rename-keys/node_modules/kind-of": { + "version": "3.2.2", + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/deepmerge": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz", - "integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/define-data-property": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", - "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.1", "gopd": "^1.0.1", @@ -5060,9 +3899,8 @@ }, "node_modules/define-properties": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", @@ -5077,53 +3915,36 @@ }, "node_modules/delayed-stream": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.4.0" } }, "node_modules/dequal": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/des.js": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", - "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0" } }, - "node_modules/detab": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/detab/-/detab-2.0.4.tgz", - "integrity": "sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g==", - "dev": true, - "dependencies": { - "repeat-string": "^1.5.4" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/detect-node": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + "license": "MIT" }, "node_modules/devlop": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", - "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dev": true, + "license": "MIT", "dependencies": { "dequal": "^2.0.0" }, @@ -5134,26 +3955,23 @@ }, "node_modules/diff": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } }, "node_modules/diff-sequences": { "version": "26.6.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10.14.2" } }, "node_modules/diffie-hellman": { "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, + "license": "MIT", "dependencies": { "bn.js": "^4.1.0", "miller-rabin": "^4.0.0", @@ -5162,15 +3980,13 @@ }, "node_modules/diffie-hellman/node_modules/bn.js": { "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/dir-glob": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, + "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, @@ -5180,8 +3996,7 @@ }, "node_modules/dnd-core": { "version": "14.0.1", - "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-14.0.1.tgz", - "integrity": "sha512-+PVS2VPTgKFPYWo3vAFEA8WPbTf7/xo43TifH9G8S1KqnrQu0o77A3unrF5yOugy4mIz7K5wAVFHUcha7wsz6A==", + "license": "MIT", "dependencies": { "@react-dnd/asap": "^4.0.0", "@react-dnd/invariant": "^2.0.0", @@ -5190,9 +4005,8 @@ }, "node_modules/doctrine": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -5202,14 +4016,12 @@ }, "node_modules/dom-accessibility-api": { "version": "0.5.16", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/dom-helpers": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", - "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" @@ -5217,9 +4029,8 @@ }, "node_modules/domain-browser": { "version": "4.23.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-4.23.0.tgz", - "integrity": "sha512-ArzcM/II1wCCujdCNyQjXrAFwS4mrLh4C7DZWlaI8mdh7h3BfKdNd3bKXITfl2PT9FtfQqaGvhi1vPRQPimjGA==", "dev": true, + "license": "Artistic-2.0", "engines": { "node": ">=10" }, @@ -5229,18 +4040,16 @@ }, "node_modules/dot-case": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", "dev": true, + "license": "MIT", "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" } }, "node_modules/dotenv": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", - "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "version": "16.4.1", + "license": "BSD-2-Clause", "engines": { "node": ">=12" }, @@ -5250,8 +4059,7 @@ }, "node_modules/dotenv-flow": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/dotenv-flow/-/dotenv-flow-4.0.1.tgz", - "integrity": "sha512-HuCQ487bSA43mtlxdWpyk5jt5Lljy+v1I8y/2l96gtjSve9p3OvJZCCOhQnz2hY4VhLogFfXpY20zBygMwaydA==", + "license": "MIT", "dependencies": { "dotenv": "^16.0.0" }, @@ -5259,16 +4067,19 @@ "node": ">= 12.0.0" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "dev": true, + "license": "MIT" + }, "node_modules/electron-to-chromium": { - "version": "1.4.616", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.616.tgz", - "integrity": "sha512-1n7zWYh8eS0L9Uy+GskE0lkBUNK83cXTVJI0pU3mGprFsbfSdAc15VTFbo+A+Bq4pwstmL30AVcEU3Fo463lNg==" + "version": "1.4.648", + "license": "ISC" }, "node_modules/elliptic": { "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", "dev": true, + "license": "MIT", "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", @@ -5281,24 +4092,18 @@ }, "node_modules/elliptic/node_modules/bn.js": { "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "node_modules/emoji-regex": { + "version": "9.2.2", "dev": true, - "engines": { - "node": ">= 4" - } + "license": "MIT" }, "node_modules/enquirer": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", - "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-colors": "^4.1.1", "strip-ansi": "^6.0.1" @@ -5307,27 +4112,28 @@ "node": ">=8.6" } }, + "node_modules/entities": { + "version": "4.5.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/error-ex": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } }, - "node_modules/error-stack-parser": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", - "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", - "dependencies": { - "stackframe": "^1.3.4" - } - }, "node_modules/es-abstract": { "version": "1.22.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", - "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", "dev": true, + "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.0", "arraybuffer.prototype.slice": "^1.0.2", @@ -5378,9 +4184,8 @@ }, "node_modules/es-get-iterator": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.3", @@ -5398,9 +4203,8 @@ }, "node_modules/es-iterator-helpers": { "version": "1.0.15", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz", - "integrity": "sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==", "dev": true, + "license": "MIT", "dependencies": { "asynciterator.prototype": "^1.0.0", "call-bind": "^1.0.2", @@ -5420,9 +4224,8 @@ }, "node_modules/es-set-tostringtag": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", - "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.2", "has-tostringtag": "^1.0.0", @@ -5434,18 +4237,16 @@ }, "node_modules/es-shim-unscopables": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", "dev": true, + "license": "MIT", "dependencies": { "hasown": "^2.0.0" } }, "node_modules/es-to-primitive": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, + "license": "MIT", "dependencies": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -5459,11 +4260,9 @@ } }, "node_modules/esbuild": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.11.tgz", - "integrity": "sha512-HJ96Hev2hX/6i5cDVwcqiJBBtuo9+FeIJOtZ9W1kA5M6AMJRHUZlpYZ1/SbEwtO0ioNAW8rUooVpC/WehY2SfA==", + "version": "0.19.12", "hasInstallScript": true, - "peer": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -5471,43 +4270,41 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.19.11", - "@esbuild/android-arm": "0.19.11", - "@esbuild/android-arm64": "0.19.11", - "@esbuild/android-x64": "0.19.11", - "@esbuild/darwin-arm64": "0.19.11", - "@esbuild/darwin-x64": "0.19.11", - "@esbuild/freebsd-arm64": "0.19.11", - "@esbuild/freebsd-x64": "0.19.11", - "@esbuild/linux-arm": "0.19.11", - "@esbuild/linux-arm64": "0.19.11", - "@esbuild/linux-ia32": "0.19.11", - "@esbuild/linux-loong64": "0.19.11", - "@esbuild/linux-mips64el": "0.19.11", - "@esbuild/linux-ppc64": "0.19.11", - "@esbuild/linux-riscv64": "0.19.11", - "@esbuild/linux-s390x": "0.19.11", - "@esbuild/linux-x64": "0.19.11", - "@esbuild/netbsd-x64": "0.19.11", - "@esbuild/openbsd-x64": "0.19.11", - "@esbuild/sunos-x64": "0.19.11", - "@esbuild/win32-arm64": "0.19.11", - "@esbuild/win32-ia32": "0.19.11", - "@esbuild/win32-x64": "0.19.11" + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.12" } }, "node_modules/escalade": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/escape-string-regexp": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", "engines": { "node": ">=10" }, @@ -5517,9 +4314,8 @@ }, "node_modules/eslint": { "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "7.12.11", "@eslint/eslintrc": "^0.4.3", @@ -5574,9 +4370,8 @@ }, "node_modules/eslint-plugin-prettier": { "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz", - "integrity": "sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==", "dev": true, + "license": "MIT", "dependencies": { "prettier-linter-helpers": "^1.0.0" }, @@ -5595,9 +4390,8 @@ }, "node_modules/eslint-plugin-react": { "version": "7.33.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz", - "integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==", "dev": true, + "license": "MIT", "dependencies": { "array-includes": "^3.1.6", "array.prototype.flatmap": "^1.3.1", @@ -5623,11 +4417,19 @@ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" } }, + "node_modules/eslint-plugin-react/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/eslint-plugin-react/node_modules/doctrine": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -5635,11 +4437,21 @@ "node": ">=0.10.0" } }, + "node_modules/eslint-plugin-react/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/eslint-plugin-react/node_modules/resolve": { "version": "2.0.0-next.5", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", "dev": true, + "license": "MIT", "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -5652,11 +4464,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/eslint-scope": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -5667,18 +4486,16 @@ }, "node_modules/eslint-scope/node_modules/estraverse": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/eslint-utils": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", "dev": true, + "license": "MIT", "dependencies": { "eslint-visitor-keys": "^1.1.0" }, @@ -5691,18 +4508,16 @@ }, "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=4" } }, "node_modules/eslint-visitor-keys": { "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -5712,76 +4527,41 @@ }, "node_modules/eslint/node_modules/@babel/code-frame": { "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/highlight": "^7.10.4" } }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/eslint/node_modules/argparse": { + "version": "1.0.10", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "sprintf-js": "~1.0.2" } }, - "node_modules/eslint/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", "dev": true, + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/eslint/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/eslint/node_modules/eslint-visitor-keys": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10" } }, "node_modules/eslint/node_modules/globals": { "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -5792,68 +4572,41 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "node_modules/eslint/node_modules/ignore": { + "version": "4.0.6", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } }, - "node_modules/eslint/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "node_modules/eslint/node_modules/js-yaml": { + "version": "3.14.1", "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" + "argparse": "^1.0.7", + "esprima": "^4.0.0" }, "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", "dev": true, + "license": "ISC", "dependencies": { - "has-flag": "^4.0.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=8" + "node": "*" } }, "node_modules/eslint/node_modules/type-fest": { "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -5861,17 +4614,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/espree": { "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "acorn": "^7.4.0", "acorn-jsx": "^5.3.1", @@ -5883,18 +4629,16 @@ }, "node_modules/espree/node_modules/eslint-visitor-keys": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=4" } }, "node_modules/esprima": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, + "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -5905,9 +4649,8 @@ }, "node_modules/esquery": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -5917,9 +4660,8 @@ }, "node_modules/esrecurse": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -5929,17 +4671,16 @@ }, "node_modules/estraverse": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/estree-util-attach-comments": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", - "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", + "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "^1.0.0" }, @@ -5950,8 +4691,8 @@ }, "node_modules/estree-util-build-jsx": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", - "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", + "dev": true, + "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", "devlop": "^1.0.0", @@ -5963,18 +4704,10 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/estree-util-build-jsx/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, "node_modules/estree-util-is-identifier-name": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", - "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "dev": true, + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" @@ -5982,8 +4715,8 @@ }, "node_modules/estree-util-to-js": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", - "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", + "dev": true, + "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", "astring": "^1.8.0", @@ -5996,16 +4729,16 @@ }, "node_modules/estree-util-to-js/node_modules/source-map": { "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">= 8" } }, "node_modules/estree-util-visit": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", - "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", + "dev": true, + "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/unist": "^3.0.0" @@ -6015,52 +4748,45 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/estree-util-visit/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + "version": "3.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } }, "node_modules/esutils": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/eventemitter3": { "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + "license": "MIT" }, "node_modules/events": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.x" } }, "node_modules/eventsource": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", - "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", + "license": "MIT", "engines": { "node": ">=12.0.0" } }, "node_modules/evp_bytestokey": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "dev": true, + "license": "MIT", "dependencies": { "md5.js": "^1.3.4", "safe-buffer": "^5.1.1" @@ -6068,33 +4794,28 @@ }, "node_modules/extend": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + "license": "MIT" }, "node_modules/fast-deep-equal": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "license": "MIT" }, "node_modules/fast-diff": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/fast-equals": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.0.1.tgz", - "integrity": "sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==", + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/fast-glob": { "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -6108,29 +4829,25 @@ }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fastq": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", - "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "version": "1.17.0", "dev": true, + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } }, "node_modules/faye-websocket": { "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "license": "Apache-2.0", "dependencies": { "websocket-driver": ">=0.5.1" }, @@ -6140,45 +4857,20 @@ }, "node_modules/fd-slicer": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", "dev": true, + "license": "MIT", "dependencies": { "pend": "~1.2.0" } }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, "node_modules/fflate": { "version": "0.4.8", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", - "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==" + "license": "MIT" }, "node_modules/file-entry-cache": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, + "license": "MIT", "dependencies": { "flat-cache": "^3.0.4" }, @@ -6186,16 +4878,37 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/fill-range": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/find-root": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + "license": "MIT" + }, + "node_modules/find-up": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } }, "node_modules/flat-cache": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, + "license": "MIT", "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", @@ -6207,24 +4920,36 @@ }, "node_modules/flatted": { "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/for-each": { "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", "dev": true, + "license": "MIT", "dependencies": { "is-callable": "^1.1.3" } }, + "node_modules/foreground-child": { + "version": "3.1.1", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/form-data": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dev": true, + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -6234,27 +4959,15 @@ "node": ">= 6" } }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, "node_modules/formik": { "version": "2.4.5", - "resolved": "https://registry.npmjs.org/formik/-/formik-2.4.5.tgz", - "integrity": "sha512-Gxlht0TD3vVdzMDHwkiNZqJ7Mvg77xQNfmBRrNtvzcHZs72TJppSTDKHpImCMJZwcWPBJ8jSQQ95GJzXFf1nAQ==", "funding": [ { "type": "individual", "url": "https://opencollective.com/formik" } ], + "license": "Apache-2.0", "dependencies": { "@types/hoist-non-react-statics": "^3.3.1", "deepmerge": "^2.1.1", @@ -6269,24 +4982,34 @@ "react": ">=16.8.0" } }, + "node_modules/fs-extra": { + "version": "11.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + "license": "ISC" }, "node_modules/function-bind": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/function.prototype.name": { "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -6302,32 +5025,28 @@ }, "node_modules/functional-red-black-tree": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/functions-have-names": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/gensync": { "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/get-intrinsic": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", "dev": true, + "license": "MIT", "dependencies": { "function-bind": "^1.1.2", "has-proto": "^1.0.1", @@ -6340,9 +5059,8 @@ }, "node_modules/get-symbol-description": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" @@ -6355,19 +5073,21 @@ } }, "node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "version": "10.3.10", "dev": true, + "license": "ISC", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": ">=12" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -6375,9 +5095,8 @@ }, "node_modules/glob-parent": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -6385,40 +5104,17 @@ "node": ">= 6" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/globals": { "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/globalthis": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", "dev": true, + "license": "MIT", "dependencies": { "define-properties": "^1.1.3" }, @@ -6431,15 +5127,13 @@ }, "node_modules/globalyzer": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", - "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/globby": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, + "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -6457,15 +5151,13 @@ }, "node_modules/globrex": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", - "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/gopd": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -6475,47 +5167,42 @@ }, "node_modules/graceful-fs": { "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/graphemer": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/hard-rejection": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/has-bigints": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "version": "4.0.0", + "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/has-property-descriptors": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.2" }, @@ -6525,9 +5212,8 @@ }, "node_modules/has-proto": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -6537,9 +5223,8 @@ }, "node_modules/has-symbols": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -6549,9 +5234,8 @@ }, "node_modules/has-tostringtag": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", "dev": true, + "license": "MIT", "dependencies": { "has-symbols": "^1.0.2" }, @@ -6564,9 +5248,8 @@ }, "node_modules/hash-base": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.4", "readable-stream": "^3.6.0", @@ -6576,45 +5259,10 @@ "node": ">=4" } }, - "node_modules/hash-base/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/hash-base/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/hash.js": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" @@ -6622,8 +5270,7 @@ }, "node_modules/hasown": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -6631,114 +5278,103 @@ "node": ">= 0.4" } }, - "node_modules/hast-to-hyperscript": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz", - "integrity": "sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA==", + "node_modules/hast-util-is-element": { + "version": "3.0.0", "dev": true, + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.3", - "comma-separated-tokens": "^1.0.0", - "property-information": "^5.3.0", - "space-separated-tokens": "^1.0.0", - "style-to-object": "^0.3.0", - "unist-util-is": "^4.0.0", - "web-namespaces": "^1.0.0" + "@types/hast": "^3.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-from-parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-6.0.1.tgz", - "integrity": "sha512-jeJUWiN5pSxW12Rh01smtVkZgZr33wBokLzKLwinYOUfSzm1Nl/c3GUGebDyOKjdsRgMvoVbV0VpAcpjF4NrJA==", + "node_modules/hast-util-to-estree": { + "version": "3.1.0", "dev": true, + "license": "MIT", "dependencies": { - "@types/parse5": "^5.0.0", - "hastscript": "^6.0.0", - "property-information": "^5.0.0", - "vfile": "^4.0.0", - "vfile-location": "^3.2.0", - "web-namespaces": "^1.0.0" + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-attach-comments": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^0.4.0", + "unist-util-position": "^5.0.0", + "zwitch": "^2.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-from-parse5/node_modules/is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "engines": { - "node": ">=4" - } - }, - "node_modules/hast-util-from-parse5/node_modules/unist-util-stringify-position": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", - "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.0", "dev": true, + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.2" + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-from-parse5/node_modules/vfile": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", - "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", + "node_modules/hast-util-to-jsx-runtime/node_modules/inline-style-parser": { + "version": "0.2.2", + "dev": true, + "license": "MIT" + }, + "node_modules/hast-util-to-jsx-runtime/node_modules/style-to-object": { + "version": "1.0.5", "dev": true, + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^2.0.0", - "vfile-message": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "inline-style-parser": "0.2.2" } }, - "node_modules/hast-util-from-parse5/node_modules/vfile-message": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", - "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "node_modules/hast-util-to-text": { + "version": "4.0.0", "dev": true, + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-stringify-position": "^2.0.0" + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "hast-util-is-element": "^3.0.0", + "unist-util-find-after": "^5.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-is-element": { + "node_modules/hast-util-whitespace": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", - "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", "dev": true, + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" }, @@ -6747,51 +5383,85 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-is-element/node_modules/@types/hast": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", - "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", + "node_modules/highlight.js": { + "version": "11.9.0", "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/history": { + "version": "4.10.1", + "license": "MIT", "dependencies": { - "@types/unist": "*" + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" } }, - "node_modules/hast-util-parse-selector": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", - "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", + "node_modules/hmac-drbg": { + "version": "1.0.1", "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" } }, - "node_modules/hast-util-raw": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-6.0.1.tgz", - "integrity": "sha512-ZMuiYA+UF7BXBtsTBNcLBF5HzXzkyE6MLzJnL605LKE8GJylNjGc4jjxazAHUtcwT5/CEt6afRKViYB4X66dig==", + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "license": "MIT" + }, + "node_modules/hosted-git-info": { + "version": "3.0.8", "dev": true, + "license": "ISC", "dependencies": { - "@types/hast": "^2.0.0", - "hast-util-from-parse5": "^6.0.0", - "hast-util-to-parse5": "^6.0.0", - "html-void-elements": "^1.0.0", - "parse5": "^6.0.0", - "unist-util-position": "^3.0.0", - "vfile": "^4.0.0", - "web-namespaces": "^1.0.0", - "xtend": "^4.0.0", - "zwitch": "^1.0.0" + "lru-cache": "^6.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=10" } }, - "node_modules/hast-util-raw/node_modules/is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "license": "MIT" + }, + "node_modules/https-browserify": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/ieee754": { + "version": "1.2.1", "dev": true, "funding": [ { @@ -6807,630 +5477,468 @@ "url": "https://feross.org/support" } ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.0", + "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">= 4" } }, - "node_modules/hast-util-raw/node_modules/unist-util-stringify-position": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", - "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", - "dev": true, + "node_modules/import-fresh": { + "version": "3.3.0", + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.2" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/hast-util-raw/node_modules/vfile": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", - "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", + "node_modules/imurmurhash": { + "version": "0.1.4", "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "license": "ISC", "dependencies": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^2.0.0", - "vfile-message": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "once": "^1.3.0", + "wrappy": "1" } }, - "node_modules/hast-util-raw/node_modules/vfile-message": { + "node_modules/inherits": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", - "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "license": "ISC" + }, + "node_modules/initials": { + "version": "3.1.2", + "license": "MIT" + }, + "node_modules/inline-style-parser": { + "version": "0.1.1", + "license": "MIT" + }, + "node_modules/internal-slot": { + "version": "1.0.6", "dev": true, + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-stringify-position": "^2.0.0" + "get-intrinsic": "^1.2.2", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">= 0.4" } }, - "node_modules/hast-util-to-estree": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.0.tgz", - "integrity": "sha512-lfX5g6hqVh9kjS/B9E2gSkvHH4SZNiQFiqWS0x9fENzEl+8W12RqdRxX6d/Cwxi30tPQs3bIO+aolQJNp1bIyw==", + "node_modules/internmap": { + "version": "2.0.3", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/intl-messageformat": { + "version": "9.13.0", + "license": "BSD-3-Clause", "dependencies": { - "@types/estree": "^1.0.0", - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "devlop": "^1.0.0", - "estree-util-attach-comments": "^3.0.0", - "estree-util-is-identifier-name": "^3.0.0", - "hast-util-whitespace": "^3.0.0", - "mdast-util-mdx-expression": "^2.0.0", - "mdast-util-mdx-jsx": "^3.0.0", - "mdast-util-mdxjs-esm": "^2.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0", - "style-to-object": "^0.4.0", - "unist-util-position": "^5.0.0", - "zwitch": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "@formatjs/ecma402-abstract": "1.11.4", + "@formatjs/fast-memoize": "1.2.1", + "@formatjs/icu-messageformat-parser": "2.1.0", + "tslib": "^2.1.0" } }, - "node_modules/hast-util-to-estree/node_modules/@types/hast": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", - "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", + "node_modules/intl-messageformat/node_modules/@formatjs/ecma402-abstract": { + "version": "1.11.4", + "license": "MIT", "dependencies": { - "@types/unist": "*" + "@formatjs/intl-localematcher": "0.2.25", + "tslib": "^2.1.0" } }, - "node_modules/hast-util-to-estree/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "node_modules/intl-messageformat/node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.1.0", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.4", + "@formatjs/icu-skeleton-parser": "1.3.6", + "tslib": "^2.1.0" + } }, - "node_modules/hast-util-to-estree/node_modules/comma-separated-tokens": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", - "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/intl-messageformat/node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.3.6", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.4", + "tslib": "^2.1.0" } }, - "node_modules/hast-util-to-estree/node_modules/hast-util-whitespace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", - "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "node_modules/intl-messageformat/node_modules/@formatjs/intl-localematcher": { + "version": "0.2.25", + "license": "MIT", "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "tslib": "^2.1.0" } }, - "node_modules/hast-util-to-estree/node_modules/property-information": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.4.0.tgz", - "integrity": "sha512-9t5qARVofg2xQqKtytzt+lZ4d1Qvj8t5B8fEwXK6qOfgRLgH/b13QlgEyDh033NOS31nXeFbYv7CLUDG1CeifQ==", + "node_modules/is-alphabetical": { + "version": "2.0.1", + "dev": true, + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/hast-util-to-estree/node_modules/space-separated-tokens": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", - "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/hast-util-to-estree/node_modules/style-to-object": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.4.tgz", - "integrity": "sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==", + "node_modules/is-arguments": { + "version": "1.1.1", + "dev": true, + "license": "MIT", "dependencies": { - "inline-style-parser": "0.1.1" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hast-util-to-estree/node_modules/unist-util-position": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", - "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "node_modules/is-array-buffer": { + "version": "3.0.2", + "dev": true, + "license": "MIT", "dependencies": { - "@types/unist": "^3.0.0" + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hast-util-to-estree/node_modules/zwitch": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", - "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } + "node_modules/is-arrayish": { + "version": "0.2.1", + "license": "MIT" }, - "node_modules/hast-util-to-jsx-runtime": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.0.tgz", - "integrity": "sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ==", - "dependencies": { - "@types/estree": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "devlop": "^1.0.0", - "estree-util-is-identifier-name": "^3.0.0", - "hast-util-whitespace": "^3.0.0", - "mdast-util-mdx-expression": "^2.0.0", - "mdast-util-mdx-jsx": "^3.0.0", - "mdast-util-mdxjs-esm": "^2.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0", - "style-to-object": "^1.0.0", - "unist-util-position": "^5.0.0", - "vfile-message": "^4.0.0" + "node_modules/is-async-function": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hast-util-to-jsx-runtime/node_modules/@types/hast": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", - "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", + "node_modules/is-bigint": { + "version": "1.0.4", + "dev": true, + "license": "MIT", "dependencies": { - "@types/unist": "*" + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hast-util-to-jsx-runtime/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, - "node_modules/hast-util-to-jsx-runtime/node_modules/comma-separated-tokens": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", - "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/is-binary-path": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/hast-util-to-jsx-runtime/node_modules/hast-util-whitespace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", - "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "node_modules/is-boolean-object": { + "version": "1.1.2", + "dev": true, + "license": "MIT", "dependencies": { - "@types/hast": "^3.0.0" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hast-util-to-jsx-runtime/node_modules/inline-style-parser": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.2.tgz", - "integrity": "sha512-EcKzdTHVe8wFVOGEYXiW9WmJXPjqi1T+234YpJr98RiFYKHV3cdy1+3mkTE+KHTHxFFLH51SfaGOoUdW+v7ViQ==" + "node_modules/is-buffer": { + "version": "1.1.6", + "license": "MIT" }, - "node_modules/hast-util-to-jsx-runtime/node_modules/property-information": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.4.0.tgz", - "integrity": "sha512-9t5qARVofg2xQqKtytzt+lZ4d1Qvj8t5B8fEwXK6qOfgRLgH/b13QlgEyDh033NOS31nXeFbYv7CLUDG1CeifQ==", + "node_modules/is-callable": { + "version": "1.2.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hast-util-to-jsx-runtime/node_modules/space-separated-tokens": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", - "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "node_modules/is-core-module": { + "version": "2.13.1", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hast-util-to-jsx-runtime/node_modules/style-to-object": { + "node_modules/is-date-object": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.5.tgz", - "integrity": "sha512-rDRwHtoDD3UMMrmZ6BzOW0naTjMsVZLIjsGleSKS/0Oz+cgCfAPRspaqJuE8rDzpKha/nEvnM0IF4seEAZUTKQ==", + "dev": true, + "license": "MIT", "dependencies": { - "inline-style-parser": "0.2.2" + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hast-util-to-jsx-runtime/node_modules/unist-util-position": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", - "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", - "dependencies": { - "@types/unist": "^3.0.0" - }, + "node_modules/is-decimal": { + "version": "2.0.1", + "dev": true, + "license": "MIT", "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/hast-util-to-parse5": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz", - "integrity": "sha512-Lu5m6Lgm/fWuz8eWnrKezHtVY83JeRGaNQ2kn9aJgqaxvVkFCZQBEhgodZUDUvoodgyROHDb3r5IxAEdl6suJQ==", + "node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.0.2", "dev": true, + "license": "MIT", "dependencies": { - "hast-to-hyperscript": "^9.0.0", - "property-information": "^5.0.0", - "web-namespaces": "^1.0.0", - "xtend": "^4.0.0", - "zwitch": "^1.0.0" + "call-bind": "^1.0.2" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hast-util-to-text": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.0.tgz", - "integrity": "sha512-EWiE1FSArNBPUo1cKWtzqgnuRQwEeQbQtnFJRYV1hb1BWDgrAlBU0ExptvZMM/KSA82cDpm2sFGf3Dmc5Mza3w==", + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", "dev": true, + "license": "MIT", "dependencies": { - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "hast-util-is-element": "^3.0.0", - "unist-util-find-after": "^5.0.0" + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hast-util-to-text/node_modules/@types/hast": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", - "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", + "node_modules/is-glob": { + "version": "4.0.3", "dev": true, + "license": "MIT", "dependencies": { - "@types/unist": "*" + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/hast-util-to-text/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==", - "dev": true - }, - "node_modules/hast-util-whitespace": { + "node_modules/is-hexadecimal": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz", - "integrity": "sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==", + "dev": true, + "license": "MIT", "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/hastscript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", - "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "node_modules/is-map": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-nan": { + "version": "1.3.2", "dev": true, + "license": "MIT", "dependencies": { - "@types/hast": "^2.0.0", - "comma-separated-tokens": "^1.0.0", - "hast-util-parse-selector": "^2.0.0", - "property-information": "^5.0.0", - "space-separated-tokens": "^1.0.0" + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/highlight.js": { - "version": "11.9.0", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.9.0.tgz", - "integrity": "sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==", + "node_modules/is-negative-zero": { + "version": "2.0.2", "dev": true, + "license": "MIT", "engines": { - "node": ">=12.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/history": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", - "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", - "dependencies": { - "@babel/runtime": "^7.1.2", - "loose-envify": "^1.2.0", - "resolve-pathname": "^3.0.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0", - "value-equal": "^1.0.1" + "node_modules/is-number": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" } }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "node_modules/is-number-object": { + "version": "1.0.7", "dev": true, + "license": "MIT", "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "dependencies": { - "react-is": "^16.7.0" + "node_modules/is-plain-obj": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/hoist-non-react-statics/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/hosted-git-info": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz", - "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", + "node_modules/is-reference": { + "version": "3.0.2", "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" + "@types/estree": "*" } }, - "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/is-regex": { + "version": "1.1.4", "dev": true, + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hosted-git-info/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/html-void-elements": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz", - "integrity": "sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==", + "node_modules/is-set": { + "version": "2.0.2", "dev": true, + "license": "MIT", "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/http-parser-js": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" - }, - "node_modules/https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", - "dev": true - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/immer": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/immer/-/immer-10.0.3.tgz", - "integrity": "sha512-pwupu3eWfouuaowscykeckFmVTpqbzW+rXFCX8rQLkZzM9ftBmU/++Ra+o+L27mz03zJTlyV4UUr+fdKNffo4A==", - "optional": true, - "peer": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "license": "MIT", "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" + "call-bind": "^1.0.2" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/initials": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/initials/-/initials-3.1.2.tgz", - "integrity": "sha512-Sltg35nx8+GX1w4U86rmbxFEmqFiSuMJviS6cB2KChB+jcT2/8Td+nlImXD74HkqpZF5PMv8hN57AyrA/7ltXw==" - }, - "node_modules/inline-style-parser": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", - "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" - }, - "node_modules/internal-slot": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", - "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", + "node_modules/is-string": { + "version": "1.0.7", "dev": true, + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.2", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" + "has-tostringtag": "^1.0.0" }, "engines": { "node": ">= 0.4" - } - }, - "node_modules/internmap": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", - "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==" - }, - "node_modules/intl-messageformat": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-9.13.0.tgz", - "integrity": "sha512-7sGC7QnSQGa5LZP7bXLDhVDtQOeKGeBFGHF2Y8LVBwYZoQZCgWeKoPGTa5GMG8g/TzDgeXuYJQis7Ggiw2xTOw==", - "dependencies": { - "@formatjs/ecma402-abstract": "1.11.4", - "@formatjs/fast-memoize": "1.2.1", - "@formatjs/icu-messageformat-parser": "2.1.0", - "tslib": "^2.1.0" - } - }, - "node_modules/intl-messageformat/node_modules/@formatjs/ecma402-abstract": { - "version": "1.11.4", - "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.4.tgz", - "integrity": "sha512-EBikYFp2JCdIfGEb5G9dyCkTGDmC57KSHhRQOC3aYxoPWVZvfWCDjZwkGYHN7Lis/fmuWl906bnNTJifDQ3sXw==", - "dependencies": { - "@formatjs/intl-localematcher": "0.2.25", - "tslib": "^2.1.0" - } - }, - "node_modules/intl-messageformat/node_modules/@formatjs/icu-messageformat-parser": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.1.0.tgz", - "integrity": "sha512-Qxv/lmCN6hKpBSss2uQ8IROVnta2r9jd3ymUEIjm2UyIkUCHVcbUVRGL/KS/wv7876edvsPe+hjHVJ4z8YuVaw==", - "dependencies": { - "@formatjs/ecma402-abstract": "1.11.4", - "@formatjs/icu-skeleton-parser": "1.3.6", - "tslib": "^2.1.0" - } - }, - "node_modules/intl-messageformat/node_modules/@formatjs/icu-skeleton-parser": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.6.tgz", - "integrity": "sha512-I96mOxvml/YLrwU2Txnd4klA7V8fRhb6JG/4hm3VMNmeJo1F03IpV2L3wWt7EweqNLES59SZ4d6hVOPCSf80Bg==", - "dependencies": { - "@formatjs/ecma402-abstract": "1.11.4", - "tslib": "^2.1.0" - } - }, - "node_modules/intl-messageformat/node_modules/@formatjs/intl-localematcher": { - "version": "0.2.25", - "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.25.tgz", - "integrity": "sha512-YmLcX70BxoSopLFdLr1Ds99NdlTI2oWoLbaUW2M406lxOIPzE1KQhRz2fPUkq34xVZQaihCoU29h0KK7An3bhA==", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/is-alphabetical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", - "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-alphanumerical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", - "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", - "dev": true, - "dependencies": { - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "node_modules/is-symbol": { + "version": "1.0.4", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "has-symbols": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -7439,4804 +5947,2845 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "node_modules/is-typed-array": { + "version": "1.1.12", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" - }, - "node_modules/is-async-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", - "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "node_modules/is-weakmap": { + "version": "2.0.1", "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "node_modules/is-weakref": { + "version": "1.0.2", "dev": true, + "license": "MIT", "dependencies": { - "has-bigints": "^1.0.1" + "call-bind": "^1.0.2" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "node_modules/is-weakset": { + "version": "2.0.2", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "get-intrinsic": "^1.1.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + "node_modules/isarray": { + "version": "2.0.5", + "dev": true, + "license": "MIT" }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/isomorphic-timers-promises": { + "version": "1.0.1", "dev": true, + "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=10" } }, - "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "node_modules/iterator.prototype": { + "version": "1.1.2", + "dev": true, + "license": "MIT", "dependencies": { - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" } }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "node_modules/jackspeak": { + "version": "2.3.6", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "has-tostringtag": "^1.0.0" + "@isaacs/cliui": "^8.0.2" }, "engines": { - "node": ">= 0.4" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-decimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", - "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "node_modules/jest-diff": { + "version": "26.6.2", "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 10.14.2" } }, - "node_modules/is-finalizationregistry": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", - "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "node_modules/jest-diff/node_modules/pretty-format": { + "version": "26.6.2", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2" + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">= 10" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/jest-diff/node_modules/react-is": { + "version": "17.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-get-type": { + "version": "26.3.0", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 10.14.2" } }, - "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "node_modules/js-sha3": { + "version": "0.8.0", + "license": "MIT" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "argparse": "^2.0.1" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" + "node_modules/jsesc": { + "version": "2.5.2", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/is-hexadecimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", - "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", + "node_modules/json-buffer": { + "version": "3.0.1", "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } + "license": "MIT" }, - "node_modules/is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "MIT" }, - "node_modules/is-nan": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", - "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3" + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=6" } }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "node_modules/jsonfile": { + "version": "6.1.0", "dev": true, - "engines": { - "node": ">= 0.4" + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "node_modules/jsx-ast-utils": { + "version": "3.3.5", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=4.0" } }, - "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "node_modules/keyv": { + "version": "4.5.4", "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-reference": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", - "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "license": "MIT", "dependencies": { - "@types/estree": "*" + "json-buffer": "3.0.1" } }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "node_modules/kind-of": { + "version": "6.0.3", "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, + "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node_modules/kleur": { + "version": "4.1.5", + "license": "MIT", + "engines": { + "node": ">=6" } }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "node_modules/latinize": { + "version": "0.5.0", "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "BSD" }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "node_modules/levn": { + "version": "0.4.1", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 0.8.0" } }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "node_modules/lines-and-columns": { + "version": "1.2.4", + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", "dev": true, + "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" + "p-locate": "^4.1.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "node_modules/lodash": { + "version": "4.17.21", + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", "dev": true, - "dependencies": { - "which-typed-array": "^1.1.11" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "MIT" }, - "node_modules/is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "node_modules/lodash.truncate": { + "version": "4.4.2", + "dev": true, + "license": "MIT" + }, + "node_modules/longest-streak": { + "version": "3.1.0", "dev": true, + "license": "MIT", "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, + "node_modules/loose-envify": { + "version": "1.4.0", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2" + "js-tokens": "^3.0.0 || ^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "bin": { + "loose-envify": "cli.js" } }, - "node_modules/is-weakset": { + "node_modules/lower-case": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "tslib": "^2.0.3" } }, - "node_modules/is-whitespace-character": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz", - "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==", + "node_modules/lowlight": { + "version": "3.1.0", "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.0.0", + "highlight.js": "~11.9.0" + }, "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-word-character": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz", - "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/lru-cache": { + "version": "5.1.1", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" } }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/isomorphic-timers-promises": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/isomorphic-timers-promises/-/isomorphic-timers-promises-1.0.1.tgz", - "integrity": "sha512-u4sej9B1LPSxTGKB/HiuzvEQnXH0ECYkSVQU39koSwmFAxhlEAFl9RdTvLv4TOTQUgBS5O3O5fwUxk6byBZ+IQ==", + "node_modules/lz-string": { + "version": "1.5.0", "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/iterator.prototype": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", - "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "reflect.getprototypeof": "^1.0.4", - "set-function-name": "^2.0.1" + "license": "MIT", + "bin": { + "lz-string": "bin/bin.js" } }, - "node_modules/jest-diff": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", + "node_modules/magic-string": { + "version": "0.30.5", "dev": true, + "license": "MIT", "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "@jridgewell/sourcemap-codec": "^1.4.15" }, "engines": { - "node": ">= 10.14.2" + "node": ">=12" } }, - "node_modules/jest-diff/node_modules/ansi-styles": { + "node_modules/map-obj": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, + "license": "MIT", "engines": { "node": ">=8" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-diff/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/markdown-extensions": { + "version": "2.0.0", "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=16" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-diff/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "node_modules/match-sorter": { + "version": "6.3.3", + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-diff/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-diff/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" + "@babel/runtime": "^7.23.8", + "remove-accents": "0.5.0" } }, - "node_modules/jest-diff/node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "node_modules/md5.js": { + "version": "1.3.5", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": ">= 10" + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" } }, - "node_modules/jest-diff/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest-diff/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, + "node_modules/mdast-util-definitions": { + "version": "5.1.2", + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "unist-util-visit": "^4.0.0" }, - "engines": { - "node": ">=8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true, - "engines": { - "node": ">= 10.14.2" + "node_modules/mdast-util-definitions/node_modules/@types/mdast": { + "version": "3.0.15", + "license": "MIT", + "dependencies": { + "@types/unist": "^2" } }, - "node_modules/js-sha3": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "node_modules/mdast-util-definitions/node_modules/@types/unist": { + "version": "2.0.10", + "license": "MIT" }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, + "node_modules/mdast-util-definitions/node_modules/unist-util-is": { + "version": "5.2.1", + "license": "MIT", "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "@types/unist": "^2.0.0" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "bin": { - "jsesc": "bin/jsesc" + "node_modules/mdast-util-definitions/node_modules/unist-util-visit": { + "version": "4.1.2", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" }, - "engines": { - "node": ">=4" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "bin": { - "json5": "lib/cli.js" + "node_modules/mdast-util-definitions/node_modules/unist-util-visit-parents": { + "version": "5.1.3", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" }, - "engines": { - "node": ">=6" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "node_modules/mdast-util-from-markdown": { + "version": "2.0.0", "dev": true, + "license": "MIT", "dependencies": { - "universalify": "^2.0.0" + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jsx-ast-utils": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", - "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "node_modules/mdast-util-mdx": { + "version": "3.0.0", "dev": true, + "license": "MIT", "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "object.assign": "^4.1.4", - "object.values": "^1.1.6" + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, - "engines": { - "node": ">=4.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.0", "dev": true, + "license": "MIT", "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/kleur": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", - "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", - "engines": { - "node": ">=6" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/latinize": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/latinize/-/latinize-0.5.0.tgz", - "integrity": "sha512-SHzxgdcFP/64lUEfX3183QALY2KdSQxad3gmhCc/b03QN1mbx0AnJWvsQjqoJLbucY9pJuK+NMbnasUIocDmnQ==", - "dev": true - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "node_modules/mdast-util-mdx-jsx": { + "version": "3.0.0", "dev": true, + "license": "MIT", "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-remove-position": "^5.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" }, - "engines": { - "node": ">= 0.8.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" - }, - "node_modules/loader-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", "dev": true, + "license": "MIT", "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true - }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", - "dev": true - }, - "node_modules/longest-streak": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", - "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "node_modules/mdast-util-phrasing": { + "version": "4.0.0", "dev": true, + "license": "MIT", "dependencies": { - "tslib": "^2.0.3" + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/lowlight": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-3.1.0.tgz", - "integrity": "sha512-CEbNVoSikAxwDMDPjXlqlFYiZLkDJHwyGu/MfOsJnF3d7f3tds5J3z8s/l9TMXhzfsJCCJEAsD78842mwmg0PQ==", + "node_modules/mdast-util-to-hast": { + "version": "13.1.0", "dev": true, + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", "devlop": "^1.0.0", - "highlight.js": "~11.9.0" + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/lowlight/node_modules/@types/hast": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", - "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", + "node_modules/mdast-util-to-markdown": { + "version": "2.1.0", "dev": true, + "license": "MIT", "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/lz-string": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", - "dev": true, - "bin": { - "lz-string": "bin/bin.js" + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/magic-string": { - "version": "0.30.5", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", - "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", + "node_modules/mdast-util-to-string": { + "version": "4.0.0", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" + "@types/mdast": "^4.0.0" }, - "engines": { - "node": ">=12" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/map-obj": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", - "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "node_modules/meow": { + "version": "9.0.0", "dev": true, + "license": "MIT", + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize": "^1.2.0", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/markdown-escapes": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz", - "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==", + "node_modules/merge2": { + "version": "1.4.1", "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "license": "MIT", + "engines": { + "node": ">= 8" } }, - "node_modules/markdown-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", - "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node_modules/micromark": { + "version": "4.0.0", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/match-sorter": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/match-sorter/-/match-sorter-6.3.1.tgz", - "integrity": "sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw==", + "node_modules/micromark-core-commonmark": { + "version": "2.0.0", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.12.5", - "remove-accents": "0.4.2" + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "node_modules/micromark-extension-mdx-expression": { + "version": "3.0.0", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/mdast-squeeze-paragraphs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-squeeze-paragraphs/-/mdast-squeeze-paragraphs-4.0.0.tgz", - "integrity": "sha512-zxdPn69hkQ1rm4J+2Cs2j6wDEv7O17TfXTJ33tl/+JPIoEmtV9t2ZzBM5LPHE8QlHsmVD8t3vPKCyY3oH+H8MQ==", + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.0", "dev": true, + "license": "MIT", "dependencies": { - "unist-util-remove": "^2.0.0" + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-definitions": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz", - "integrity": "sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ==", + "node_modules/micromark-extension-mdx-md": { + "version": "2.0.0", "dev": true, + "license": "MIT", "dependencies": { - "unist-util-visit": "^2.0.0" + "micromark-util-types": "^2.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-from-markdown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.0.tgz", - "integrity": "sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA==", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark": "^4.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-stringify-position": "^4.0.0" + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-from-markdown/node_modules/@types/mdast": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz", - "integrity": "sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/mdast-util-from-markdown/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, - "node_modules/mdast-util-mdx": { + "node_modules/micromark-extension-mdxjs-esm": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", - "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", + "dev": true, + "license": "MIT", "dependencies": { - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-mdx-expression": "^2.0.0", - "mdast-util-mdx-jsx": "^3.0.0", - "mdast-util-mdxjs-esm": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-mdx-expression": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz", - "integrity": "sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw==", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" + "node_modules/micromark-extension-mdxjs/node_modules/acorn": { + "version": "8.11.3", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=0.4.0" } }, - "node_modules/mdast-util-mdx-expression/node_modules/@types/hast": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", - "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", + "node_modules/micromark-factory-destination": { + "version": "2.0.0", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "@types/unist": "*" + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/mdast-util-mdx-expression/node_modules/@types/mdast": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz", - "integrity": "sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==", + "node_modules/micromark-factory-label": { + "version": "2.0.0", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "@types/unist": "*" + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/mdast-util-mdx-jsx": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.0.0.tgz", - "integrity": "sha512-XZuPPzQNBPAlaqsTTgRrcJnyFbSOBovSadFgbFu8SnuNgm+6Bdx1K+IWoitsmj6Lq6MNtI+ytOqwN70n//NaBA==", + "node_modules/micromark-factory-mdx-expression": { + "version": "2.0.1", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "ccount": "^2.0.0", - "devlop": "^1.1.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "parse-entities": "^4.0.0", - "stringify-entities": "^4.0.0", - "unist-util-remove-position": "^5.0.0", - "unist-util-stringify-position": "^4.0.0", + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-mdx-jsx/node_modules/@types/hast": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", - "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", + "node_modules/micromark-factory-space": { + "version": "2.0.0", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "@types/unist": "*" + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/mdast-util-mdx-jsx/node_modules/@types/mdast": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz", - "integrity": "sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==", + "node_modules/micromark-factory-title": { + "version": "2.0.0", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, - "node_modules/mdast-util-mdx-jsx/node_modules/ccount": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", - "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/character-entities": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", - "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/mdast-util-mdx-jsx/node_modules/character-entities-legacy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", - "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/micromark-factory-whitespace": { + "version": "2.0.0", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/mdast-util-mdx-jsx/node_modules/character-reference-invalid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", - "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/micromark-util-character": { + "version": "2.1.0", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/mdast-util-mdx-jsx/node_modules/is-alphabetical": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", - "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/micromark-util-chunked": { + "version": "2.0.0", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/mdast-util-mdx-jsx/node_modules/is-alphanumerical": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", - "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", - "dependencies": { - "is-alphabetical": "^2.0.0", - "is-decimal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/micromark-util-classify-character": { + "version": "2.0.0", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/mdast-util-mdx-jsx/node_modules/is-decimal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", - "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.0", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/mdast-util-mdx-jsx/node_modules/is-hexadecimal": { + "node_modules/micromark-util-decode-numeric-character-reference": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", - "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/parse-entities": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz", - "integrity": "sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "character-entities": "^2.0.0", - "character-entities-legacy": "^3.0.0", - "character-reference-invalid": "^2.0.0", - "decode-named-character-reference": "^1.0.0", - "is-alphanumerical": "^2.0.0", - "is-decimal": "^2.0.0", - "is-hexadecimal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/mdast-util-mdx-jsx/node_modules/parse-entities/node_modules/@types/unist": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", - "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==" - }, - "node_modules/mdast-util-mdx-jsx/node_modules/unist-util-is": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", - "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "node_modules/micromark-util-decode-string": { + "version": "2.0.0", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/mdast-util-mdx-jsx/node_modules/unist-util-remove-position": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", - "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-visit": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } + "node_modules/micromark-util-encode": { + "version": "2.0.0", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" }, - "node_modules/mdast-util-mdx-jsx/node_modules/unist-util-visit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", - "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "node_modules/micromark-util-events-to-acorn": { + "version": "2.0.2", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" } }, - "node_modules/mdast-util-mdx-jsx/node_modules/unist-util-visit-parents": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", - "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.0", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" }, - "node_modules/mdast-util-mdxjs-esm": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", - "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.0", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/mdast-util-mdxjs-esm/node_modules/@types/hast": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", - "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", + "node_modules/micromark-util-resolve-all": { + "version": "2.0.0", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "@types/unist": "*" + "micromark-util-types": "^2.0.0" } }, - "node_modules/mdast-util-mdxjs-esm/node_modules/@types/mdast": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz", - "integrity": "sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==", + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.0", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "@types/unist": "*" + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/mdast-util-phrasing": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.0.0.tgz", - "integrity": "sha512-xadSsJayQIucJ9n053dfQwVu1kuXg7jCTdYsMK8rqzKZh52nLfSH/k0sAxE0u+pj/zKZX+o5wB+ML5mRayOxFA==", + "node_modules/micromark-util-subtokenize": { + "version": "2.0.0", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "@types/mdast": "^4.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/mdast-util-phrasing/node_modules/@types/mdast": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz", - "integrity": "sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==", - "dependencies": { - "@types/unist": "*" - } + "node_modules/micromark-util-symbol": { + "version": "2.0.0", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" }, - "node_modules/mdast-util-phrasing/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "node_modules/micromark-util-types": { + "version": "2.0.0", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" }, - "node_modules/mdast-util-phrasing/node_modules/unist-util-is": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", - "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "node_modules/micromatch": { + "version": "4.0.5", + "dev": true, + "license": "MIT", "dependencies": { - "@types/unist": "^3.0.0" + "braces": "^3.0.2", + "picomatch": "^2.3.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=8.6" } }, - "node_modules/mdast-util-to-hast": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-10.0.1.tgz", - "integrity": "sha512-BW3LM9SEMnjf4HXXVApZMt8gLQWVNXc3jryK0nJu/rOXPOnlkUjmdkDlmxMirpbU9ILncGFIwLH/ubnWBbcdgA==", + "node_modules/microseconds": { + "version": "0.2.0", + "license": "MIT" + }, + "node_modules/miller-rabin": { + "version": "4.0.1", "dev": true, + "license": "MIT", "dependencies": { - "@types/mdast": "^3.0.0", - "@types/unist": "^2.0.0", - "mdast-util-definitions": "^4.0.0", - "mdurl": "^1.0.0", - "unist-builder": "^2.0.0", - "unist-util-generated": "^1.0.0", - "unist-util-position": "^3.0.0", - "unist-util-visit": "^2.0.0" + "bn.js": "^4.0.0", + "brorand": "^1.0.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "bin": { + "miller-rabin": "bin/miller-rabin" } }, - "node_modules/mdast-util-to-markdown": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz", - "integrity": "sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "longest-streak": "^3.0.0", - "mdast-util-phrasing": "^4.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark-util-decode-string": "^2.0.0", - "unist-util-visit": "^5.0.0", - "zwitch": "^2.0.0" + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.0", + "dev": true, + "license": "MIT" + }, + "node_modules/mime": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=10.0.0" } }, - "node_modules/mdast-util-to-markdown/node_modules/@types/mdast": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz", - "integrity": "sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==", - "dependencies": { - "@types/unist": "*" + "node_modules/mime-db": { + "version": "1.52.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "node_modules/mdast-util-to-markdown/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, - "node_modules/mdast-util-to-markdown/node_modules/unist-util-is": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", - "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "node_modules/mime-types": { + "version": "2.1.35", + "dev": true, + "license": "MIT", "dependencies": { - "@types/unist": "^3.0.0" + "mime-db": "1.52.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">= 0.6" } }, - "node_modules/mdast-util-to-markdown/node_modules/unist-util-visit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", - "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "node_modules/min-indent": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" } }, - "node_modules/mdast-util-to-markdown/node_modules/unist-util-visit-parents": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", - "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "dev": true, + "license": "ISC" }, - "node_modules/mdast-util-to-markdown/node_modules/zwitch": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", - "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "dev": true, + "license": "MIT" }, - "node_modules/mdast-util-to-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "node_modules/minimatch": { + "version": "9.0.3", + "dev": true, + "license": "ISC", "dependencies": { - "@types/mdast": "^4.0.0" + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/mdast-util-to-string/node_modules/@types/mdast": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz", - "integrity": "sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==", - "dependencies": { - "@types/unist": "*" + "node_modules/minimist": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", - "dev": true - }, - "node_modules/meow": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", - "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", + "node_modules/minimist-options": { + "version": "4.1.0", "dev": true, + "license": "MIT", "dependencies": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize": "^1.2.0", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.18.0", - "yargs-parser": "^20.2.3" + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 6" } }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "node_modules/minipass": { + "version": "7.0.4", "dev": true, + "license": "ISC", "engines": { - "node": ">= 8" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/micromark": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", - "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/mri": { + "version": "1.2.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "license": "MIT" + }, + "node_modules/nano-time": { + "version": "1.0.0", + "license": "ISC", "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "big-integer": "^1.6.16" } }, - "node_modules/micromark-core-commonmark": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.0.tgz", - "integrity": "sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA==", + "node_modules/nanoclone": { + "version": "0.2.1", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.7", "funding": [ { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" + "type": "github", + "url": "https://github.com/sponsors/ai" } ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/micromark-extension-mdx-expression": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.0.tgz", - "integrity": "sha512-sI0nwhUDz97xyzqJAbHQhp5TfaxEvZZZ2JDqUo+7NvyIYG6BZ5CPPqj2ogUoPJlmXHBnyZUzISg9+oUmU6tUjQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/natural-compare": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/no-case": { + "version": "3.0.4", + "dev": true, + "license": "MIT", "dependencies": { - "@types/estree": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-mdx-expression": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-events-to-acorn": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "lower-case": "^2.0.2", + "tslib": "^2.0.3" } }, - "node_modules/micromark-extension-mdx-jsx": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.0.tgz", - "integrity": "sha512-uvhhss8OGuzR4/N17L1JwvmJIpPhAd8oByMawEKx6NVdBCbesjH4t+vjEp3ZXft9DwvlKSD07fCeI44/N0Vf2w==", + "node_modules/node-fetch": { + "version": "2.7.0", + "dev": true, + "license": "MIT", "dependencies": { - "@types/acorn": "^4.0.0", - "@types/estree": "^1.0.0", - "devlop": "^1.0.0", - "estree-util-is-identifier-name": "^3.0.0", - "micromark-factory-mdx-expression": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "vfile-message": "^4.0.0" + "whatwg-url": "^5.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } } }, - "node_modules/micromark-extension-mdx-md": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", - "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", + "node_modules/node-releases": { + "version": "2.0.14", + "license": "MIT" + }, + "node_modules/node-stdlib-browser": { + "version": "1.2.0", + "dev": true, + "license": "MIT", "dependencies": { - "micromark-util-types": "^2.0.0" + "assert": "^2.0.0", + "browser-resolve": "^2.0.0", + "browserify-zlib": "^0.2.0", + "buffer": "^5.7.1", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "create-require": "^1.1.1", + "crypto-browserify": "^3.11.0", + "domain-browser": "^4.22.0", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "isomorphic-timers-promises": "^1.0.1", + "os-browserify": "^0.3.0", + "path-browserify": "^1.0.1", + "pkg-dir": "^5.0.0", + "process": "^0.11.10", + "punycode": "^1.4.1", + "querystring-es3": "^0.2.1", + "readable-stream": "^3.6.0", + "stream-browserify": "^3.0.0", + "stream-http": "^3.2.0", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.1", + "url": "^0.11.0", + "util": "^0.12.4", + "vm-browserify": "^1.0.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=10" } }, - "node_modules/micromark-extension-mdxjs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", - "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", + "node_modules/node-stdlib-browser/node_modules/punycode": { + "version": "1.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-package-data": { + "version": "3.0.3", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.0.0", - "acorn-jsx": "^5.0.0", - "micromark-extension-mdx-expression": "^3.0.0", - "micromark-extension-mdx-jsx": "^3.0.0", - "micromark-extension-mdx-md": "^2.0.0", - "micromark-extension-mdxjs-esm": "^3.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-types": "^2.0.0" + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=10" } }, - "node_modules/micromark-extension-mdxjs-esm": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", - "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", + "node_modules/normalize-package-data/node_modules/hosted-git-info": { + "version": "4.1.0", + "dev": true, + "license": "ISC", "dependencies": { - "@types/estree": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-events-to-acorn": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-position-from-estree": "^2.0.0", - "vfile-message": "^4.0.0" + "lru-cache": "^6.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=10" } }, - "node_modules/micromark-extension-mdxjs/node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "bin": { - "acorn": "bin/acorn" + "node_modules/normalize-package-data/node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" }, "engines": { - "node": ">=0.4.0" + "node": ">=10" } }, - "node_modules/micromark-factory-destination": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", - "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "node_modules/normalize-package-data/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/micromark-factory-label": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", - "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" + "node_modules/notistack": { + "version": "2.0.8", + "license": "MIT", + "dependencies": { + "clsx": "^1.1.0", + "hoist-non-react-statics": "^3.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/notistack" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "@mui/material": "^5.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" + "@emotion/styled": { + "optional": true } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" } }, - "node_modules/micromark-factory-mdx-expression": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.1.tgz", - "integrity": "sha512-F0ccWIUHRLRrYp5TC9ZYXmZo+p2AM13ggbsW4T0b5CRKP8KHVRB8t4pwtBgTxtjRmwrK0Irwm7vs2JOZabHZfg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "@types/estree": "^1.0.0", - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-events-to-acorn": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-position-from-estree": "^2.0.0", - "vfile-message": "^4.0.0" + "node_modules/object-assign": { + "version": "4.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-title": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", - "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-whitespace": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", - "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-character": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", - "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-chunked": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", - "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-classify-character": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", - "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-combine-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", - "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", - "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", - "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", - "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-util-events-to-acorn": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.2.tgz", - "integrity": "sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "@types/acorn": "^4.0.0", - "@types/estree": "^1.0.0", - "@types/unist": "^3.0.0", - "devlop": "^1.0.0", - "estree-util-visit": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "vfile-message": "^4.0.0" - } - }, - "node_modules/micromark-util-events-to-acorn/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, - "node_modules/micromark-util-html-tag-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", - "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-util-normalize-identifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", - "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-resolve-all": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", - "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-sanitize-uri": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", - "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-subtokenize": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.0.tgz", - "integrity": "sha512-vc93L1t+gpR3p8jxeVdaYlbV2jTYteDje19rNSS/H5dlhxUYll5Fy6vJ2cDwP8RnsXi818yGty1ayP55y3W6fg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/micromatch/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/micromatch/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/micromatch/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/micromatch/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/microseconds": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/microseconds/-/microseconds-0.2.0.tgz", - "integrity": "sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==" - }, - "node_modules/miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "dev": true, - "dependencies": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "bin": { - "miller-rabin": "bin/miller-rabin" - } - }, - "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - }, - "node_modules/mime": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", - "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", - "dev": true - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minimist-options": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", - "dev": true, - "dependencies": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/minimist-options/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mri": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", - "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/nano-time": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/nano-time/-/nano-time-1.0.0.tgz", - "integrity": "sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA==", - "dependencies": { - "big-integer": "^1.6.16" - } - }, - "node_modules/nanoclone": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/nanoclone/-/nanoclone-0.2.1.tgz", - "integrity": "sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==" - }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "peer": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "dev": true, - "dependencies": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - } - }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-fetch": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.0.tgz", - "integrity": "sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, - "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" - }, - "node_modules/node-stdlib-browser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/node-stdlib-browser/-/node-stdlib-browser-1.2.0.tgz", - "integrity": "sha512-VSjFxUhRhkyed8AtLwSCkMrJRfQ3e2lGtG3sP6FEgaLKBBbxM/dLfjRe1+iLhjvyLFW3tBQ8+c0pcOtXGbAZJg==", - "dev": true, - "dependencies": { - "assert": "^2.0.0", - "browser-resolve": "^2.0.0", - "browserify-zlib": "^0.2.0", - "buffer": "^5.7.1", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "create-require": "^1.1.1", - "crypto-browserify": "^3.11.0", - "domain-browser": "^4.22.0", - "events": "^3.0.0", - "https-browserify": "^1.0.0", - "isomorphic-timers-promises": "^1.0.1", - "os-browserify": "^0.3.0", - "path-browserify": "^1.0.1", - "pkg-dir": "^5.0.0", - "process": "^0.11.10", - "punycode": "^1.4.1", - "querystring-es3": "^0.2.1", - "readable-stream": "^3.6.0", - "stream-browserify": "^3.0.0", - "stream-http": "^3.2.0", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", - "tty-browserify": "0.0.1", - "url": "^0.11.0", - "util": "^0.12.4", - "vm-browserify": "^1.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-stdlib-browser/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/node-stdlib-browser/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/node-stdlib-browser/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/node-stdlib-browser/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/node-stdlib-browser/node_modules/pkg-dir": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", - "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", - "dev": true, - "dependencies": { - "find-up": "^5.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-stdlib-browser/node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", - "dev": true - }, - "node_modules/node-stdlib-browser/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/normalize-package-data/node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/normalize-package-data/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/normalize-package-data/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/notistack": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/notistack/-/notistack-2.0.8.tgz", - "integrity": "sha512-/IY14wkFp5qjPgKNvAdfL5Jp6q90+MjgKTPh4c81r/lW70KeuX6b9pE/4f8L4FG31cNudbN9siiFS5ql1aSLRw==", - "dependencies": { - "clsx": "^1.1.0", - "hoist-non-react-statics": "^3.3.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/notistack" - }, - "peerDependencies": { - "@emotion/react": "^11.4.1", - "@emotion/styled": "^11.3.0", - "@mui/material": "^5.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@emotion/react": { - "optional": true - }, - "@emotion/styled": { - "optional": true - } - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", - "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", - "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.hasown": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz", - "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.values": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", - "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/oblivious-set": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/oblivious-set/-/oblivious-set-1.0.0.tgz", - "integrity": "sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==" - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/openapi-typescript": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-4.5.0.tgz", - "integrity": "sha512-++gWZLTKmbZP608JHMerllAs84HzULWfVjfH7otkWBLrKxUvzHMFqI6R4JSW1LoNDZnS4KKiRTZW66Fxyp6z4Q==", - "dev": true, - "dependencies": { - "hosted-git-info": "^3.0.8", - "js-yaml": "^4.1.0", - "kleur": "^4.1.4", - "meow": "^9.0.0", - "mime": "^3.0.0", - "node-fetch": "^2.6.6", - "prettier": "^2.5.1", - "slash": "^3.0.0", - "tiny-glob": "^0.2.9" - }, - "bin": { - "openapi-typescript": "bin/cli.js" - }, - "engines": { - "node": ">= 12.0.0", - "npm": ">= 7.0.0" - } - }, - "node_modules/openapi-typescript/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/openapi-typescript/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/openapi-typescript/node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/openapi-typescript/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true - }, - "node_modules/openapi-typescript/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true - }, - "node_modules/openapi-typescript/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dev": true, - "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", - "dev": true - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-asn1": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", - "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", - "dev": true, - "dependencies": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" - } - }, - "node_modules/parse-entities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", - "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", - "dev": true, - "dependencies": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "node_modules/path-browserify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", - "dev": true - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "node_modules/path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dependencies": { - "isarray": "0.0.1" - } - }, - "node_modules/path-to-regexp/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", - "dev": true, - "dependencies": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true - }, - "node_modules/periscopic": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", - "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^3.0.0", - "is-reference": "^3.0.0" - } - }, - "node_modules/periscopic/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/posthog-js": { - "version": "1.96.1", - "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.96.1.tgz", - "integrity": "sha512-kv1vQqYMt2BV3YHS+wxsbGuP+tz+M3y1AzNhz8TfkpY1HT8W/ONT0i0eQpeRr9Y+d4x/fZ6M4cXG5GMvi9lRCA==", - "dependencies": { - "fflate": "^0.4.1" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/pretty-format/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/prism-react-renderer": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-1.2.1.tgz", - "integrity": "sha512-w23ch4f75V1Tnz8DajsYKvY5lF7H1+WvzvLUcF0paFxkTHSp42RS0H5CttdN2Q8RR3DRGZ9v5xD/h3n8C8kGmg==", - "peerDependencies": { - "react": ">=0.14.9" - } - }, - "node_modules/prism-svelte": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/prism-svelte/-/prism-svelte-0.4.7.tgz", - "integrity": "sha512-yABh19CYbM24V7aS7TuPYRNMqthxwbvx6FF/Rw920YbyBWO3tnyPIqRMgHuSVsLmuHkkBS1Akyof463FVdkeDQ==" - }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "dev": true, - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/prop-types/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/property-expr": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", - "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==" - }, - "node_modules/property-information": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", - "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", - "dev": true, - "dependencies": { - "xtend": "^4.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "dev": true, - "dependencies": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/public-encrypt/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pure-color": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/pure-color/-/pure-color-1.3.0.tgz", - "integrity": "sha512-QFADYnsVoBMw1srW7OVKEYjG+MbIa49s54w1MA1EDY6r2r/sTcKKYqRX1f4GYvnXP7eN/Pe9HFcX+hwzmrXRHA==" - }, - "node_modules/qr.js": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/qr.js/-/qr.js-0.0.0.tgz", - "integrity": "sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ==" - }, - "node_modules/qs": { - "version": "6.11.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", - "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", - "dev": true, - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "dev": true, - "dependencies": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "node_modules/react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-codemirror2": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/react-codemirror2/-/react-codemirror2-7.3.0.tgz", - "integrity": "sha512-gCgJPXDX+5iaPolkHAu1YbJ92a2yL7Je4TuyO3QEqOtI/d6mbEk08l0oIm18R4ctuT/Sl87X63xIMBnRQBXYXA==", - "peerDependencies": { - "codemirror": "5.x", - "react": ">=15.5 <=17.x" - } - }, - "node_modules/react-cropper": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/react-cropper/-/react-cropper-2.1.8.tgz", - "integrity": "sha512-QEj6CE9et/gMRqpaKMgZQdBgtzLjjq+zj1pmHwtoWG6GqscDl4QpTwoEElWN2pieYxkwFaZa0lPiD2b9nwqLKQ==", - "dependencies": { - "cropperjs": "^1.5.12" - }, - "peerDependencies": { - "react": ">=16.0.0" - } - }, - "node_modules/react-dnd": { - "version": "14.0.5", - "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-14.0.5.tgz", - "integrity": "sha512-9i1jSgbyVw0ELlEVt/NkCUkxy1hmhJOkePoCH713u75vzHGyXhPDm28oLfc2NMSBjZRM1Y+wRjHXJT3sPrTy+A==", - "dependencies": { - "@react-dnd/invariant": "^2.0.0", - "@react-dnd/shallowequal": "^2.0.0", - "dnd-core": "14.0.1", - "fast-deep-equal": "^3.1.3", - "hoist-non-react-statics": "^3.3.2" - }, - "peerDependencies": { - "@types/hoist-non-react-statics": ">= 3.3.1", - "@types/node": ">= 12", - "@types/react": ">= 16", - "react": ">= 16.14" - }, - "peerDependenciesMeta": { - "@types/hoist-non-react-statics": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-dnd-html5-backend": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-14.1.0.tgz", - "integrity": "sha512-6ONeqEC3XKVf4eVmMTe0oPds+c5B9Foyj8p/ZKLb7kL2qh9COYxiBHv3szd6gztqi/efkmriywLUVlPotqoJyw==", - "dependencies": { - "dnd-core": "14.0.1" - } - }, - "node_modules/react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" - }, - "peerDependencies": { - "react": "17.0.2" - } - }, - "node_modules/react-dom/node_modules/scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "node_modules/react-draggable": { - "version": "4.4.6", - "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.6.tgz", - "integrity": "sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==", - "dependencies": { - "clsx": "^1.1.1", - "prop-types": "^15.8.1" - }, - "peerDependencies": { - "react": ">= 16.3.0", - "react-dom": ">= 16.3.0" - } - }, - "node_modules/react-fast-compare": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz", - "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==" - }, - "node_modules/react-google-recaptcha-v3": { - "version": "1.9.5", - "resolved": "https://registry.npmjs.org/react-google-recaptcha-v3/-/react-google-recaptcha-v3-1.9.5.tgz", - "integrity": "sha512-WmrhBMCnJovUPdA5S+9SmYlPTPIDXmUJWlHlOnJAXdU0cyZcVkqwln3kIj/NLl8Y6HH/4lKgno5N/e1N+fEtfg==", - "dependencies": { - "hoist-non-react-statics": "^3.3.2" - }, - "peerDependencies": { - "react": "^17.0", - "react-dom": "^17.0" - } - }, - "node_modules/react-gtm-module": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/react-gtm-module/-/react-gtm-module-2.0.11.tgz", - "integrity": "sha512-8gyj4TTxeP7eEyc2QKawEuQoAZdjKvMY4pgWfycGmqGByhs17fR+zEBs0JUDq4US/l+vbTl+6zvUIx27iDo/Vw==" - }, - "node_modules/react-helmet": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-6.1.0.tgz", - "integrity": "sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==", - "dependencies": { - "object-assign": "^4.1.1", - "prop-types": "^15.7.2", - "react-fast-compare": "^3.1.1", - "react-side-effect": "^2.1.0" - }, - "peerDependencies": { - "react": ">=16.3.0" - } - }, - "node_modules/react-helmet/node_modules/react-fast-compare": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", - "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" - }, - "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, - "node_modules/react-lifecycles-compat": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", - "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" - }, - "node_modules/react-list": { - "version": "0.8.17", - "resolved": "https://registry.npmjs.org/react-list/-/react-list-0.8.17.tgz", - "integrity": "sha512-pgmzGi0G5uGrdHzMhgO7KR1wx5ZXVvI3SsJUmkblSAKtewIhMwbQiMuQiTE83ozo04BQJbe0r3WIWzSO0dR1xg==", - "dependencies": { - "prop-types": "15" - }, - "peerDependencies": { - "react": "0.14 || 15 - 18" - } - }, - "node_modules/react-markdown": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-8.0.7.tgz", - "integrity": "sha512-bvWbzG4MtOU62XqBx3Xx+zB2raaFFsq4mYiAzfjXJMEz2sixgeAfraA3tvzULF02ZdOMUOKTBFFaZJDDrq+BJQ==", - "dependencies": { - "@types/hast": "^2.0.0", - "@types/prop-types": "^15.0.0", - "@types/unist": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-whitespace": "^2.0.0", - "prop-types": "^15.0.0", - "property-information": "^6.0.0", - "react-is": "^18.0.0", - "remark-parse": "^10.0.0", - "remark-rehype": "^10.0.0", - "space-separated-tokens": "^2.0.0", - "style-to-object": "^0.4.0", - "unified": "^10.0.0", - "unist-util-visit": "^4.0.0", - "vfile": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - }, - "peerDependencies": { - "@types/react": ">=16", - "react": ">=16" - } - }, - "node_modules/react-markdown/node_modules/bail": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", - "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/react-markdown/node_modules/comma-separated-tokens": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", - "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/react-markdown/node_modules/is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "engines": { - "node": ">=4" - } - }, - "node_modules/react-markdown/node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/react-markdown/node_modules/mdast-util-from-markdown": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz", - "integrity": "sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==", - "dependencies": { - "@types/mdast": "^3.0.0", - "@types/unist": "^2.0.0", - "decode-named-character-reference": "^1.0.0", - "mdast-util-to-string": "^3.1.0", - "micromark": "^3.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-decode-string": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "unist-util-stringify-position": "^3.0.0", - "uvu": "^0.5.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/react-markdown/node_modules/mdast-util-to-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz", - "integrity": "sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==", - "dependencies": { - "@types/mdast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/react-markdown/node_modules/micromark": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.2.0.tgz", - "integrity": "sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "micromark-core-commonmark": "^1.0.1", - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-chunked": "^1.0.0", - "micromark-util-combine-extensions": "^1.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-encode": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-resolve-all": "^1.0.0", - "micromark-util-sanitize-uri": "^1.0.0", - "micromark-util-subtokenize": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.1", - "uvu": "^0.5.0" - } - }, - "node_modules/react-markdown/node_modules/micromark-core-commonmark": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz", - "integrity": "sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-factory-destination": "^1.0.0", - "micromark-factory-label": "^1.0.0", - "micromark-factory-space": "^1.0.0", - "micromark-factory-title": "^1.0.0", - "micromark-factory-whitespace": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-chunked": "^1.0.0", - "micromark-util-classify-character": "^1.0.0", - "micromark-util-html-tag-name": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-resolve-all": "^1.0.0", - "micromark-util-subtokenize": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.1", - "uvu": "^0.5.0" - } - }, - "node_modules/react-markdown/node_modules/micromark-factory-destination": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.1.0.tgz", - "integrity": "sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "node_modules/react-markdown/node_modules/micromark-factory-label": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.1.0.tgz", - "integrity": "sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "node_modules/react-markdown/node_modules/micromark-factory-space": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz", - "integrity": "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-types": "^1.0.0" + "node_modules/object-inspect": { + "version": "1.13.1", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/react-markdown/node_modules/micromark-factory-title": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.1.0.tgz", - "integrity": "sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/object-is": { + "version": "1.1.5", + "dev": true, + "license": "MIT", "dependencies": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/react-markdown/node_modules/micromark-factory-whitespace": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.1.0.tgz", - "integrity": "sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" + "node_modules/object-keys": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" } }, - "node_modules/react-markdown/node_modules/micromark-util-character": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz", - "integrity": "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/object.assign": { + "version": "4.1.5", + "dev": true, + "license": "MIT", "dependencies": { - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/react-markdown/node_modules/micromark-util-chunked": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz", - "integrity": "sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/object.entries": { + "version": "1.1.7", + "dev": true, + "license": "MIT", "dependencies": { - "micromark-util-symbol": "^1.0.0" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/react-markdown/node_modules/micromark-util-classify-character": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz", - "integrity": "sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/object.fromentries": { + "version": "2.0.7", + "dev": true, + "license": "MIT", "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/react-markdown/node_modules/micromark-util-combine-extensions": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.1.0.tgz", - "integrity": "sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/object.hasown": { + "version": "1.1.3", + "dev": true, + "license": "MIT", "dependencies": { - "micromark-util-chunked": "^1.0.0", - "micromark-util-types": "^1.0.0" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/react-markdown/node_modules/micromark-util-decode-numeric-character-reference": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.1.0.tgz", - "integrity": "sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/object.values": { + "version": "1.1.7", + "dev": true, + "license": "MIT", "dependencies": { - "micromark-util-symbol": "^1.0.0" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/react-markdown/node_modules/micromark-util-decode-string": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.1.0.tgz", - "integrity": "sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/oblivious-set": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/once": { + "version": "1.4.0", + "license": "ISC", "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-symbol": "^1.0.0" + "wrappy": "1" } }, - "node_modules/react-markdown/node_modules/micromark-util-encode": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz", - "integrity": "sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/react-markdown/node_modules/micromark-util-html-tag-name": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.2.0.tgz", - "integrity": "sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/react-markdown/node_modules/micromark-util-normalize-identifier": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz", - "integrity": "sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/openapi-typescript": { + "version": "4.5.0", + "dev": true, + "license": "MIT", "dependencies": { - "micromark-util-symbol": "^1.0.0" + "hosted-git-info": "^3.0.8", + "js-yaml": "^4.1.0", + "kleur": "^4.1.4", + "meow": "^9.0.0", + "mime": "^3.0.0", + "node-fetch": "^2.6.6", + "prettier": "^2.5.1", + "slash": "^3.0.0", + "tiny-glob": "^0.2.9" + }, + "bin": { + "openapi-typescript": "bin/cli.js" + }, + "engines": { + "node": ">= 12.0.0", + "npm": ">= 7.0.0" } }, - "node_modules/react-markdown/node_modules/micromark-util-resolve-all": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz", - "integrity": "sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/optionator": { + "version": "0.9.3", + "dev": true, + "license": "MIT", "dependencies": { - "micromark-util-types": "^1.0.0" + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/react-markdown/node_modules/micromark-util-sanitize-uri": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz", - "integrity": "sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/os-browserify": { + "version": "0.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/p-limit": { + "version": "2.3.0", + "dev": true, + "license": "MIT", "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-encode": "^1.0.0", - "micromark-util-symbol": "^1.0.0" + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-markdown/node_modules/micromark-util-subtokenize": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz", - "integrity": "sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/p-locate": { + "version": "4.1.0", + "dev": true, + "license": "MIT", "dependencies": { - "micromark-util-chunked": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/react-markdown/node_modules/micromark-util-symbol": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz", - "integrity": "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] + "node_modules/p-try": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } }, - "node_modules/react-markdown/node_modules/micromark-util-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", - "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] + "node_modules/pako": { + "version": "1.0.11", + "dev": true, + "license": "(MIT AND Zlib)" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-asn1": { + "version": "5.1.6", + "dev": true, + "license": "ISC", + "dependencies": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } }, - "node_modules/react-markdown/node_modules/property-information": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.4.0.tgz", - "integrity": "sha512-9t5qARVofg2xQqKtytzt+lZ4d1Qvj8t5B8fEwXK6qOfgRLgH/b13QlgEyDh033NOS31nXeFbYv7CLUDG1CeifQ==", + "node_modules/parse-entities": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/react-markdown/node_modules/remark-parse": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.2.tgz", - "integrity": "sha512-3ydxgHa/ZQzG8LvC7jTXccARYDcRld3VfcgIIFs7bI6vbRSxJJmzgLEIIoYKyrfhaY+ujuWaf/PJiMZXoiCXgw==", + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.10", + "dev": true, + "license": "MIT" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "license": "MIT", "dependencies": { - "@types/mdast": "^3.0.0", - "mdast-util-from-markdown": "^1.0.0", - "unified": "^10.0.0" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-markdown/node_modules/space-separated-tokens": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", - "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/path-browserify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/react-markdown/node_modules/style-to-object": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.4.tgz", - "integrity": "sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==", - "dependencies": { - "inline-style-parser": "0.1.1" + "node_modules/path-is-absolute": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/react-markdown/node_modules/trough": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", - "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/react-markdown/node_modules/unified": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", - "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "node_modules/path-parse": { + "version": "1.0.7", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.10.1", + "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "@types/unist": "^2.0.0", - "bail": "^2.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^5.0.0" + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/react-markdown/node_modules/unist-util-is": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", - "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.0", + "dev": true, + "license": "ISC", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-to-regexp": { + "version": "1.8.0", + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "isarray": "0.0.1" } }, - "node_modules/react-markdown/node_modules/unist-util-stringify-position": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", - "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "node_modules/path-to-regexp/node_modules/isarray": { + "version": "0.0.1", + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "dev": true, + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0" + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=0.12" } }, - "node_modules/react-markdown/node_modules/unist-util-visit": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", - "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==", + "node_modules/pend": { + "version": "1.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/periscopic": { + "version": "3.1.0", + "dev": true, + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0", - "unist-util-visit-parents": "^5.1.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "@types/estree": "^1.0.0", + "estree-walker": "^3.0.0", + "is-reference": "^3.0.0" } }, - "node_modules/react-markdown/node_modules/unist-util-visit-parents": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", - "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", - "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0" + "node_modules/picocolors": { + "version": "1.0.0", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/react-markdown/node_modules/vfile": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", - "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", + "node_modules/pkg-dir": { + "version": "5.0.0", + "dev": true, + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^3.0.0", - "vfile-message": "^3.0.0" + "find-up": "^5.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=10" } }, - "node_modules/react-markdown/node_modules/vfile-message": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", - "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", + "node_modules/pkg-dir/node_modules/find-up": { + "version": "5.0.0", + "dev": true, + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-stringify-position": "^3.0.0" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-qr-code": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/react-qr-code/-/react-qr-code-2.0.12.tgz", - "integrity": "sha512-k+pzP5CKLEGBRwZsDPp98/CAJeXlsYRHM2iZn1Sd5Th/HnKhIZCSg27PXO58zk8z02RaEryg+60xa4vyywMJwg==", + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "6.0.0", + "dev": true, + "license": "MIT", "dependencies": { - "prop-types": "^15.8.1", - "qr.js": "0.0.0" + "p-locate": "^5.0.0" }, - "peerDependencies": { - "react": "^16.x || ^17.x || ^18.x", - "react-native-svg": "*" + "engines": { + "node": ">=10" }, - "peerDependenciesMeta": { - "react-native-svg": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-query": { - "version": "3.39.3", - "resolved": "https://registry.npmjs.org/react-query/-/react-query-3.39.3.tgz", - "integrity": "sha512-nLfLz7GiohKTJDuT4us4X3h/8unOh+00MLb2yJoGTPjxKs2bc1iDhkNx2bd5MKklXnOD3NrVZ+J2UXujA5In4g==", + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "3.1.0", + "dev": true, + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.5.5", - "broadcast-channel": "^3.4.1", - "match-sorter": "^6.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" + "yocto-queue": "^0.1.0" }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "engines": { + "node": ">=10" }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-redux": { - "version": "7.2.9", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", - "integrity": "sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==", + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "5.0.0", + "dev": true, + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.15.4", - "@types/react-redux": "^7.1.20", - "hoist-non-react-statics": "^3.3.2", - "loose-envify": "^1.4.0", - "prop-types": "^15.7.2", - "react-is": "^17.0.2" - }, - "peerDependencies": { - "react": "^16.8.3 || ^17 || ^18" + "p-limit": "^3.0.2" }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - } - } - }, - "node_modules/react-redux/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" - }, - "node_modules/react-refresh": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", - "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-resize-detector": { - "version": "6.7.8", - "resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-6.7.8.tgz", - "integrity": "sha512-0FaEcUBAbn+pq3PT5a9hHRebUfuS1SRLGLpIw8LydU7zX429I6XJgKerKAMPsJH0qWAl6o5bVKNqFJqr6tGPYw==", - "dependencies": { - "@types/resize-observer-browser": "^0.1.6", - "lodash": "^4.17.21", - "resize-observer-polyfill": "^1.5.1" + "node": ">=10" }, - "peerDependencies": { - "react": "^16.0.0 || ^17.0.0", - "react-dom": "^16.0.0 || ^17.0.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-router": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", - "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", + "node_modules/postcss": { + "version": "8.4.33", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "hoist-non-react-statics": "^3.1.0", - "loose-envify": "^1.3.1", - "path-to-regexp": "^1.7.0", - "prop-types": "^15.6.2", - "react-is": "^16.6.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" }, - "peerDependencies": { - "react": ">=15" + "engines": { + "node": "^10 || ^12 || >=14" } }, - "node_modules/react-router-dom": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz", - "integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==", + "node_modules/posthog-js": { + "version": "1.103.1", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "loose-envify": "^1.3.1", - "prop-types": "^15.6.2", - "react-router": "5.3.4", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" - }, - "peerDependencies": { - "react": ">=15" - } - }, - "node_modules/react-router/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/react-side-effect": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.2.tgz", - "integrity": "sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw==", - "peerDependencies": { - "react": "^16.3.0 || ^17.0.0 || ^18.0.0" + "fflate": "^0.4.8", + "preact": "^10.19.3" } }, - "node_modules/react-smooth": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-2.0.5.tgz", - "integrity": "sha512-BMP2Ad42tD60h0JW6BFaib+RJuV5dsXJK9Baxiv/HlNFjvRLqA9xrNKxVWnUIZPQfzUwGXIlU/dSYLU+54YGQA==", - "dependencies": { - "fast-equals": "^5.0.0", - "react-transition-group": "2.9.0" - }, - "peerDependencies": { - "prop-types": "^15.6.0", - "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" + "node_modules/preact": { + "version": "10.19.3", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" } }, - "node_modules/react-smooth/node_modules/dom-helpers": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", - "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==", - "dependencies": { - "@babel/runtime": "^7.1.2" + "node_modules/prelude-ls": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/react-smooth/node_modules/react-transition-group": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", - "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==", - "dependencies": { - "dom-helpers": "^3.4.0", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2", - "react-lifecycles-compat": "^3.0.4" + "node_modules/prettier": { + "version": "2.8.8", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" }, - "peerDependencies": { - "react": ">=15.0.0", - "react-dom": ">=15.0.0" + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/react-transition-group": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", - "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "dev": true, + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.5.5", - "dom-helpers": "^5.0.1", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2" + "fast-diff": "^1.1.2" }, - "peerDependencies": { - "react": ">=16.6.0", - "react-dom": ">=16.6.0" + "engines": { + "node": ">=6.0.0" } }, - "node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "node_modules/pretty-format": { + "version": "27.5.1", "dev": true, + "license": "MIT", "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" }, "engines": { - "node": ">=8" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", "dev": true, - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/pretty-format/node_modules/react-is": { + "version": "17.0.2", "dev": true, + "license": "MIT" + }, + "node_modules/prism-react-renderer": { + "version": "2.3.1", + "license": "MIT", "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "@types/prismjs": "^1.26.0", + "clsx": "^2.0.0" }, + "peerDependencies": { + "react": ">=16.0.0" + } + }, + "node_modules/prism-react-renderer/node_modules/clsx": { + "version": "2.1.0", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/read-pkg-up/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "node_modules/process": { + "version": "0.11.10", "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 0.6.0" } }, - "node_modules/read-pkg-up/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/progress": { + "version": "2.0.3", "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "license": "MIT", "dependencies": { - "p-try": "^2.0.0" - }, + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "license": "MIT" + }, + "node_modules/property-expr": { + "version": "2.0.6", + "license": "MIT" + }, + "node_modules/property-information": { + "version": "6.4.1", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.0", + "dev": true, + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.1", + "dev": true, + "license": "MIT", "engines": { "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/read-pkg-up/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/pure-color": { + "version": "1.3.0", + "license": "MIT" + }, + "node_modules/qr.js": { + "version": "0.0.0", + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.11.2", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "p-limit": "^2.2.0" + "side-channel": "^1.0.4" }, "engines": { - "node": ">=8" + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/read-pkg-up/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "node_modules/querystring-es3": { + "version": "0.2.1", "dev": true, "engines": { - "node": ">=8" + "node": ">=0.4.x" } }, - "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "node_modules/querystringify": { + "version": "2.2.0", + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quick-lru": { + "version": "4.0.1", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "node_modules/randombytes": { + "version": "2.1.0", "dev": true, + "license": "MIT", "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "safe-buffer": "^5.1.0" } }, - "node_modules/read-pkg/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "node_modules/randomfill": { + "version": "1.0.4", "dev": true, - "bin": { - "semver": "bin/semver" + "license": "MIT", + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" } }, - "node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, + "node_modules/react": { + "version": "17.0.2", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/recharts": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.1.9.tgz", - "integrity": "sha512-VozH5uznUvGqD7n224FGj7cmMAenlS0HPCs+7r2HeeHiQK6un6z0CTZfWVAB860xbcr4m+BN/EGMPZmYWd34Rg==", - "dependencies": { - "@types/d3-interpolate": "^2.0.0", - "@types/d3-scale": "^3.0.0", - "@types/d3-shape": "^2.0.0", - "classnames": "^2.2.5", - "d3-interpolate": "^2.0.0", - "d3-scale": "^3.0.0", - "d3-shape": "^2.0.0", - "eventemitter3": "^4.0.1", - "lodash": "^4.17.19", - "react-is": "^16.10.2", - "react-resize-detector": "^6.6.3", - "react-smooth": "^2.0.0", - "recharts-scale": "^0.4.4", - "reduce-css-calc": "^2.1.8" + "node_modules/react-codemirror2": { + "version": "7.3.0", + "license": "MIT", + "peerDependencies": { + "codemirror": "5.x", + "react": ">=15.5 <=17.x" + } + }, + "node_modules/react-cropper": { + "version": "2.3.3", + "license": "MIT", + "dependencies": { + "cropperjs": "^1.5.13" }, - "engines": { - "node": ">=12" + "peerDependencies": { + "react": ">=17.0.2" + } + }, + "node_modules/react-dnd": { + "version": "14.0.5", + "license": "MIT", + "dependencies": { + "@react-dnd/invariant": "^2.0.0", + "@react-dnd/shallowequal": "^2.0.0", + "dnd-core": "14.0.1", + "fast-deep-equal": "^3.1.3", + "hoist-non-react-statics": "^3.3.2" }, "peerDependencies": { - "react": "^16.0.0 || ^17.0.0", - "react-dom": "^16.0.0 || ^17.0.0" + "@types/hoist-non-react-statics": ">= 3.3.1", + "@types/node": ">= 12", + "@types/react": ">= 16", + "react": ">= 16.14" + }, + "peerDependenciesMeta": { + "@types/hoist-non-react-statics": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@types/react": { + "optional": true + } } }, - "node_modules/recharts-scale": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", - "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", + "node_modules/react-dnd-html5-backend": { + "version": "14.1.0", + "license": "MIT", "dependencies": { - "decimal.js-light": "^2.4.1" + "dnd-core": "14.0.1" } }, - "node_modules/recharts/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + "node_modules/react-dom": { + "version": "17.0.2", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + }, + "peerDependencies": { + "react": "17.0.2" + } + }, + "node_modules/react-dom/node_modules/scheduler": { + "version": "0.20.2", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "node_modules/react-draggable": { + "version": "4.4.6", + "license": "MIT", + "dependencies": { + "clsx": "^1.1.1", + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "react": ">= 16.3.0", + "react-dom": ">= 16.3.0" + } + }, + "node_modules/react-fast-compare": { + "version": "2.0.4", + "license": "MIT" }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dev": true, + "node_modules/react-google-recaptcha-v3": { + "version": "1.9.5", + "license": "MIT", "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" + "hoist-non-react-statics": "^3.3.2" }, - "engines": { - "node": ">=8" + "peerDependencies": { + "react": "^17.0", + "react-dom": "^17.0" } }, - "node_modules/reduce-css-calc": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz", - "integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==", + "node_modules/react-gtm-module": { + "version": "2.0.11", + "license": "MIT" + }, + "node_modules/react-helmet": { + "version": "6.1.0", + "license": "MIT", "dependencies": { - "css-unit-converter": "^1.1.1", - "postcss-value-parser": "^3.3.0" + "object-assign": "^4.1.1", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.1.1", + "react-side-effect": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.3.0" } }, - "node_modules/reduce-css-calc/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + "node_modules/react-helmet/node_modules/react-fast-compare": { + "version": "3.2.2", + "license": "MIT" }, - "node_modules/redux": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", - "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "node_modules/react-is": { + "version": "18.2.0", + "license": "MIT" + }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "license": "MIT" + }, + "node_modules/react-list": { + "version": "0.8.17", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.9.2" + "prop-types": "15" + }, + "peerDependencies": { + "react": "0.14 || 15 - 18" } }, - "node_modules/redux-devtools-extension": { - "version": "2.13.9", - "resolved": "https://registry.npmjs.org/redux-devtools-extension/-/redux-devtools-extension-2.13.9.tgz", - "integrity": "sha512-cNJ8Q/EtjhQaZ71c8I9+BPySIBVEKssbPpskBfsXqb8HJ002A3KRVHfeRzwRo6mGPqsm7XuHTqNSNeS1Khig0A==", - "deprecated": "Package moved to @redux-devtools/extension.", - "dev": true, + "node_modules/react-markdown": { + "version": "8.0.7", + "license": "MIT", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/prop-types": "^15.0.0", + "@types/unist": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^2.0.0", + "prop-types": "^15.0.0", + "property-information": "^6.0.0", + "react-is": "^18.0.0", + "remark-parse": "^10.0.0", + "remark-rehype": "^10.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^0.4.0", + "unified": "^10.0.0", + "unist-util-visit": "^4.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, "peerDependencies": { - "redux": "^3.1.0 || ^4.0.0" + "@types/react": ">=16", + "react": ">=16" } }, - "node_modules/redux-promise-middleware": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/redux-promise-middleware/-/redux-promise-middleware-6.2.0.tgz", - "integrity": "sha512-TEzfMeLX63gju2WqkdFQlQMvUGYzFvJNePIJJsBlbPHs3Txsbc/5Rjhmtha1XdMU6lkeiIlp1Qx7AR3Zo9he9g==", - "peerDependencies": { - "redux": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0" + "node_modules/react-markdown/node_modules/@types/hast": { + "version": "2.3.9", + "license": "MIT", + "dependencies": { + "@types/unist": "^2" } }, - "node_modules/redux-thunk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", - "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", - "peerDependencies": { - "redux": "^4" + "node_modules/react-markdown/node_modules/@types/mdast": { + "version": "3.0.15", + "license": "MIT", + "dependencies": { + "@types/unist": "^2" } }, - "node_modules/reflect-metadata": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", - "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==" + "node_modules/react-markdown/node_modules/@types/unist": { + "version": "2.0.10", + "license": "MIT" }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz", - "integrity": "sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "globalthis": "^1.0.3", - "which-builtin-type": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, + "node_modules/react-markdown/node_modules/hast-util-whitespace": { + "version": "2.0.1", + "license": "MIT", "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" - }, + "node_modules/react-markdown/node_modules/is-buffer": { + "version": "2.0.5", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=4" } }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, + "node_modules/react-markdown/node_modules/is-plain-obj": { + "version": "4.1.0", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/rehype-highlight": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/rehype-highlight/-/rehype-highlight-7.0.0.tgz", - "integrity": "sha512-QtobgRgYoQaK6p1eSr2SD1i61f7bjF2kZHAQHxeCHAuJf7ZUDMvQ7owDq9YTkmar5m5TSUol+2D3bp3KfJf/oA==", - "dev": true, + "node_modules/react-markdown/node_modules/mdast-util-from-markdown": { + "version": "1.3.1", + "license": "MIT", "dependencies": { - "@types/hast": "^3.0.0", - "hast-util-to-text": "^4.0.0", - "lowlight": "^3.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.0" + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/rehype-highlight/node_modules/@types/hast": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", - "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", - "dev": true, - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/rehype-highlight/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==", - "dev": true - }, - "node_modules/rehype-highlight/node_modules/unist-util-is": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", - "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", - "dev": true, + "node_modules/react-markdown/node_modules/mdast-util-to-hast": { + "version": "12.3.0", + "license": "MIT", "dependencies": { - "@types/unist": "^3.0.0" + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "mdast-util-definitions": "^5.0.0", + "micromark-util-sanitize-uri": "^1.1.0", + "trim-lines": "^3.0.0", + "unist-util-generated": "^2.0.0", + "unist-util-position": "^4.0.0", + "unist-util-visit": "^4.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/rehype-highlight/node_modules/unist-util-visit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", - "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", - "dev": true, + "node_modules/react-markdown/node_modules/mdast-util-to-string": { + "version": "3.2.0", + "license": "MIT", "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" + "@types/mdast": "^3.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/rehype-highlight/node_modules/unist-util-visit-parents": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", - "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", - "dev": true, + "node_modules/react-markdown/node_modules/micromark": { + "version": "3.2.0", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/react-markdown/node_modules/micromark-core-commonmark": { + "version": "1.1.0", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-factory-destination": "^1.0.0", + "micromark-factory-label": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-factory-title": "^1.0.0", + "micromark-factory-whitespace": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-html-tag-name": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/react-markdown/node_modules/micromark-factory-destination": { + "version": "1.1.0", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-footnotes": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/remark-footnotes/-/remark-footnotes-2.0.0.tgz", - "integrity": "sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" } }, - "node_modules/remark-mdx": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-1.6.22.tgz", - "integrity": "sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ==", - "dev": true, + "node_modules/react-markdown/node_modules/micromark-factory-label": { + "version": "1.1.0", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "@babel/core": "7.12.9", - "@babel/helper-plugin-utils": "7.10.4", - "@babel/plugin-proposal-object-rest-spread": "7.12.1", - "@babel/plugin-syntax-jsx": "7.12.1", - "@mdx-js/util": "1.6.22", - "is-alphabetical": "1.0.4", - "remark-parse": "8.0.3", - "unified": "9.2.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" } }, - "node_modules/remark-mdx/node_modules/@babel/core": { - "version": "7.12.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", - "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", - "dev": true, + "node_modules/react-markdown/node_modules/micromark-factory-space": { + "version": "1.1.0", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.5", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helpers": "^7.12.5", - "@babel/parser": "^7.12.7", - "@babel/template": "^7.12.7", - "@babel/traverse": "^7.12.9", - "@babel/types": "^7.12.7", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/remark-mdx/node_modules/@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", - "dev": true - }, - "node_modules/remark-mdx/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/remark-mdx/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" } }, - "node_modules/remark-parse": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-8.0.3.tgz", - "integrity": "sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==", - "dev": true, - "dependencies": { - "ccount": "^1.0.0", - "collapse-white-space": "^1.0.2", - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-whitespace-character": "^1.0.0", - "is-word-character": "^1.0.0", - "markdown-escapes": "^1.0.0", - "parse-entities": "^2.0.0", - "repeat-string": "^1.5.4", - "state-toggle": "^1.0.0", - "trim": "0.0.1", - "trim-trailing-lines": "^1.0.0", - "unherit": "^1.0.4", - "unist-util-remove-position": "^2.0.0", - "vfile-location": "^3.0.0", - "xtend": "^4.0.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "node_modules/react-markdown/node_modules/micromark-factory-title": { + "version": "1.1.0", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" } }, - "node_modules/remark-rehype": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-10.1.0.tgz", - "integrity": "sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw==", + "node_modules/react-markdown/node_modules/micromark-factory-whitespace": { + "version": "1.1.0", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "@types/hast": "^2.0.0", - "@types/mdast": "^3.0.0", - "mdast-util-to-hast": "^12.1.0", - "unified": "^10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" } }, - "node_modules/remark-rehype/node_modules/bail": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", - "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/react-markdown/node_modules/micromark-util-character": { + "version": "1.2.0", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" } }, - "node_modules/remark-rehype/node_modules/is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "node_modules/react-markdown/node_modules/micromark-util-chunked": { + "version": "1.1.0", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/feross" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "patreon", - "url": "https://www.patreon.com/feross" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/react-markdown/node_modules/micromark-util-classify-character": { + "version": "1.1.0", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "consulting", - "url": "https://feross.org/support" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], - "engines": { - "node": ">=4" + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" } }, - "node_modules/remark-rehype/node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node_modules/react-markdown/node_modules/micromark-util-combine-extensions": { + "version": "1.1.0", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-types": "^1.0.0" } }, - "node_modules/remark-rehype/node_modules/mdast-util-definitions": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz", - "integrity": "sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==", + "node_modules/react-markdown/node_modules/micromark-util-decode-numeric-character-reference": { + "version": "1.1.0", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "@types/mdast": "^3.0.0", - "@types/unist": "^2.0.0", - "unist-util-visit": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "micromark-util-symbol": "^1.0.0" } }, - "node_modules/remark-rehype/node_modules/mdast-util-to-hast": { - "version": "12.3.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-12.3.0.tgz", - "integrity": "sha512-pits93r8PhnIoU4Vy9bjW39M2jJ6/tdHyja9rrot9uujkN7UTU9SDnE6WNJz/IGyQk3XHX6yNNtrBH6cQzm8Hw==", - "dependencies": { - "@types/hast": "^2.0.0", - "@types/mdast": "^3.0.0", - "mdast-util-definitions": "^5.0.0", - "micromark-util-sanitize-uri": "^1.1.0", - "trim-lines": "^3.0.0", - "unist-util-generated": "^2.0.0", - "unist-util-position": "^4.0.0", - "unist-util-visit": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "node_modules/react-markdown/node_modules/micromark-util-decode-string": { + "version": "1.1.0", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-symbol": "^1.0.0" } }, - "node_modules/remark-rehype/node_modules/micromark-util-character": { + "node_modules/react-markdown/node_modules/micromark-util-encode": { + "version": "1.1.0", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/react-markdown/node_modules/micromark-util-html-tag-name": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz", - "integrity": "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==", "funding": [ { "type": "GitHub Sponsors", @@ -12247,15 +8796,27 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT" + }, + "node_modules/react-markdown/node_modules/micromark-util-normalize-identifier": { + "version": "1.1.0", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" + "micromark-util-symbol": "^1.0.0" } }, - "node_modules/remark-rehype/node_modules/micromark-util-encode": { + "node_modules/react-markdown/node_modules/micromark-util-resolve-all": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz", - "integrity": "sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==", "funding": [ { "type": "GitHub Sponsors", @@ -12265,12 +8826,14 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^1.0.0" + } }, - "node_modules/remark-rehype/node_modules/micromark-util-sanitize-uri": { + "node_modules/react-markdown/node_modules/micromark-util-sanitize-uri": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz", - "integrity": "sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==", "funding": [ { "type": "GitHub Sponsors", @@ -12281,16 +8844,15 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-character": "^1.0.0", "micromark-util-encode": "^1.0.0", "micromark-util-symbol": "^1.0.0" } }, - "node_modules/remark-rehype/node_modules/micromark-util-symbol": { + "node_modules/react-markdown/node_modules/micromark-util-subtokenize": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz", - "integrity": "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==", "funding": [ { "type": "GitHub Sponsors", @@ -12300,12 +8862,17 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } }, - "node_modules/remark-rehype/node_modules/micromark-util-types": { + "node_modules/react-markdown/node_modules/micromark-util-symbol": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", - "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", "funding": [ { "type": "GitHub Sponsors", @@ -12315,21 +8882,53 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] + ], + "license": "MIT" }, - "node_modules/remark-rehype/node_modules/trough": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", - "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "node_modules/react-markdown/node_modules/micromark-util-types": { + "version": "1.1.0", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/react-markdown/node_modules/remark-parse": { + "version": "10.0.2", + "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "unified": "^10.0.0" + }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/react-markdown/node_modules/remark-rehype": { + "version": "10.1.0", + "license": "MIT", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "mdast-util-to-hast": "^12.1.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/remark-rehype/node_modules/unified": { + "node_modules/react-markdown/node_modules/unified": { "version": "10.1.2", - "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", - "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "license": "MIT", "dependencies": { "@types/unist": "^2.0.0", "bail": "^2.0.0", @@ -12344,19 +8943,9 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/remark-rehype/node_modules/unist-util-generated": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-2.0.1.tgz", - "integrity": "sha512-qF72kLmPxAw0oN2fwpWIqbXAVyEqUzDHMsbtPvOudIlUzXYFIeQIuxXQCRCFh22B7cixvU0MG7m3MW8FTq/S+A==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-rehype/node_modules/unist-util-is": { + "node_modules/react-markdown/node_modules/unist-util-is": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", - "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "license": "MIT", "dependencies": { "@types/unist": "^2.0.0" }, @@ -12365,10 +8954,9 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/remark-rehype/node_modules/unist-util-position": { + "node_modules/react-markdown/node_modules/unist-util-position": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-4.0.4.tgz", - "integrity": "sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg==", + "license": "MIT", "dependencies": { "@types/unist": "^2.0.0" }, @@ -12377,10 +8965,9 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/remark-rehype/node_modules/unist-util-stringify-position": { + "node_modules/react-markdown/node_modules/unist-util-stringify-position": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", - "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "license": "MIT", "dependencies": { "@types/unist": "^2.0.0" }, @@ -12389,10 +8976,9 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/remark-rehype/node_modules/unist-util-visit": { + "node_modules/react-markdown/node_modules/unist-util-visit": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", - "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==", + "license": "MIT", "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0", @@ -12403,10 +8989,9 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/remark-rehype/node_modules/unist-util-visit-parents": { + "node_modules/react-markdown/node_modules/unist-util-visit-parents": { "version": "5.1.3", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", - "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", + "license": "MIT", "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0" @@ -12416,10 +9001,9 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/remark-rehype/node_modules/vfile": { + "node_modules/react-markdown/node_modules/vfile": { "version": "5.3.7", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", - "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", + "license": "MIT", "dependencies": { "@types/unist": "^2.0.0", "is-buffer": "^2.0.0", @@ -12431,10 +9015,9 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/remark-rehype/node_modules/vfile-message": { + "node_modules/react-markdown/node_modules/vfile-message": { "version": "3.1.4", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", - "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", + "license": "MIT", "dependencies": { "@types/unist": "^2.0.0", "unist-util-stringify-position": "^3.0.0" @@ -12444,1246 +9027,1068 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/remark-squeeze-paragraphs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/remark-squeeze-paragraphs/-/remark-squeeze-paragraphs-4.0.0.tgz", - "integrity": "sha512-8qRqmL9F4nuLPIgl92XUuxI3pFxize+F1H0e/W3llTk0UsjJaj01+RrirkMw7P21RKe4X6goQhYRSvNWX+70Rw==", - "dev": true, - "dependencies": { - "mdast-squeeze-paragraphs": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remove-accents": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.4.2.tgz", - "integrity": "sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==" - }, - "node_modules/rename-keys": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/rename-keys/-/rename-keys-1.2.0.tgz", - "integrity": "sha512-U7XpAktpbSgHTRSNRrjKSrjYkZKuhUukfoBlXWXUExCAqhzh1TU3BDRAfJmarcl5voKS+pbKU9MvyLWKZ4UEEg==", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" - }, - "node_modules/resize-observer-polyfill": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", - "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "node_modules/react-qr-code": { + "version": "2.0.12", + "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" + "prop-types": "^15.8.1", + "qr.js": "0.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve-pathname": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", - "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rifm": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/rifm/-/rifm-0.12.1.tgz", - "integrity": "sha512-OGA1Bitg/dSJtI/c4dh90svzaUPt228kzFsUkJbtA2c964IqEAwWXeL9ZJi86xWv3j5SMqRvGULl7bA6cK0Bvg==", "peerDependencies": { - "react": ">=16.8" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" + "react": "^16.x || ^17.x || ^18.x", + "react-native-svg": "*" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "peerDependenciesMeta": { + "react-native-svg": { + "optional": true + } } }, - "node_modules/ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dev": true, + "node_modules/react-query": { + "version": "3.39.3", + "license": "MIT", "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "node_modules/rollup": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.2.tgz", - "integrity": "sha512-66RB8OtFKUTozmVEh3qyNfH+b+z2RXBVloqO2KCC/pjFaGaHtxP9fVfOQKPSGXg2mElmjmxjW/fZ7iKrEpMH5Q==", - "peer": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.9.2", - "@rollup/rollup-android-arm64": "4.9.2", - "@rollup/rollup-darwin-arm64": "4.9.2", - "@rollup/rollup-darwin-x64": "4.9.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.9.2", - "@rollup/rollup-linux-arm64-gnu": "4.9.2", - "@rollup/rollup-linux-arm64-musl": "4.9.2", - "@rollup/rollup-linux-riscv64-gnu": "4.9.2", - "@rollup/rollup-linux-x64-gnu": "4.9.2", - "@rollup/rollup-linux-x64-musl": "4.9.2", - "@rollup/rollup-win32-arm64-msvc": "4.9.2", - "@rollup/rollup-win32-ia32-msvc": "4.9.2", - "@rollup/rollup-win32-x64-msvc": "4.9.2", - "fsevents": "~2.3.2" - } - }, - "node_modules/rollup/node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" + "@babel/runtime": "^7.5.5", + "broadcast-channel": "^3.4.1", + "match-sorter": "^6.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true }, - { - "type": "consulting", - "url": "https://feross.org/support" + "react-native": { + "optional": true } - ], - "dependencies": { - "queue-microtask": "^1.2.2" } }, - "node_modules/sade": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", - "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "node_modules/react-redux": { + "version": "7.2.9", + "license": "MIT", "dependencies": { - "mri": "^1.1.0" + "@babel/runtime": "^7.15.4", + "@types/react-redux": "^7.1.20", + "hoist-non-react-statics": "^3.3.2", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^17.0.2" + }, + "peerDependencies": { + "react": "^16.8.3 || ^17 || ^18" }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/react-redux/node_modules/react-is": { + "version": "17.0.2", + "license": "MIT" + }, + "node_modules/react-refresh": { + "version": "0.14.0", + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, - "node_modules/safe-array-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", - "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", - "dev": true, + "node_modules/react-router": { + "version": "5.3.4", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "react": ">=15" } }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "dev": true, + "node_modules/react-router-dom": { + "version": "5.3.4", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.3.4", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "react": ">=15" } }, - "node_modules/safer-buffer": { + "node_modules/react-router/node_modules/react-is": { + "version": "16.13.1", + "license": "MIT" + }, + "node_modules/react-side-effect": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "license": "MIT", + "peerDependencies": { + "react": "^16.3.0 || ^17.0.0 || ^18.0.0" + } }, - "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "peer": true, + "node_modules/react-smooth": { + "version": "2.0.5", + "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0" + "fast-equals": "^5.0.0", + "react-transition-group": "2.9.0" + }, + "peerDependencies": { + "prop-types": "^15.6.0", + "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" } }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" + "node_modules/react-smooth/node_modules/dom-helpers": { + "version": "3.4.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.1.2" } }, - "node_modules/set-function-length": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", - "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", - "dev": true, + "node_modules/react-smooth/node_modules/react-transition-group": { + "version": "2.9.0", + "license": "BSD-3-Clause", "dependencies": { - "define-data-property": "^1.1.1", - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" + "dom-helpers": "^3.4.0", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2", + "react-lifecycles-compat": "^3.0.4" }, - "engines": { - "node": ">= 0.4" + "peerDependencies": { + "react": ">=15.0.0", + "react-dom": ">=15.0.0" } }, - "node_modules/set-function-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", - "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", - "dev": true, + "node_modules/react-transition-group": { + "version": "4.4.5", + "license": "BSD-3-Clause", "dependencies": { - "define-data-property": "^1.0.1", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.0" + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" }, - "engines": { - "node": ">= 0.4" + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" } }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "dev": true - }, - "node_modules/sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "node_modules/read-pkg": { + "version": "5.2.0", "dev": true, + "license": "MIT", "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" }, - "bin": { - "sha.js": "bin.js" + "engines": { + "node": ">=8" } }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/read-pkg-up": { + "version": "7.0.1", "dev": true, + "license": "MIT", "dependencies": { - "shebang-regex": "^3.0.0" + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=8" } }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "ISC" }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", "dev": true, - "engines": { - "node": ">=8" + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "node_modules/read-pkg/node_modules/semver": { + "version": "5.7.2", "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" + "license": "ISC", + "bin": { + "semver": "bin/semver" } }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/slice-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/readable-stream": { + "version": "3.6.2", "dev": true, + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "node": ">= 6" + } }, - "node_modules/snake-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", - "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "node_modules/readdirp": { + "version": "3.6.0", "dev": true, + "license": "MIT", "dependencies": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" } }, - "node_modules/sockjs-client": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.6.1.tgz", - "integrity": "sha512-2g0tjOR+fRs0amxENLi/q5TiJTqY+WXFOzb5UwXndlK6TO3U/mirZznpx6w34HVMoc3g7cY24yC/ZMIYnDlfkw==", + "node_modules/recharts": { + "version": "2.11.0", + "license": "MIT", "dependencies": { - "debug": "^3.2.7", - "eventsource": "^2.0.2", - "faye-websocket": "^0.11.4", - "inherits": "^2.0.4", - "url-parse": "^1.5.10" + "clsx": "^2.0.0", + "eventemitter3": "^4.0.1", + "lodash": "^4.17.19", + "react-is": "^16.10.2", + "react-smooth": "^2.0.5", + "recharts-scale": "^0.4.4", + "tiny-invariant": "^1.3.1", + "victory-vendor": "^36.6.8" }, "engines": { - "node": ">=12" + "node": ">=14" }, - "funding": { - "url": "https://tidelift.com/funding/github/npm/sockjs-client" + "peerDependencies": { + "prop-types": "^15.6.0", + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" } }, - "node_modules/sockjs-client/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/recharts-scale": { + "version": "0.4.5", + "license": "MIT", "dependencies": { - "ms": "^2.1.1" + "decimal.js-light": "^2.4.1" } }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "node_modules/recharts/node_modules/clsx": { + "version": "2.1.0", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "peer": true, - "engines": { - "node": ">=0.10.0" - } + "node_modules/recharts/node_modules/react-is": { + "version": "16.13.1", + "license": "MIT" }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "optional": true, - "peer": true, + "node_modules/redent": { + "version": "3.0.0", + "dev": true, + "license": "MIT", "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "optional": true, - "peer": true, + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/space-separated-tokens": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", - "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node": ">=8" } }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "dev": true, + "node_modules/redux": { + "version": "4.2.1", + "license": "MIT", "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "@babel/runtime": "^7.9.2" } }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "node_modules/redux-devtools-extension": { + "version": "2.13.9", "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "license": "MIT", + "peerDependencies": { + "redux": "^3.1.0 || ^4.0.0" } }, - "node_modules/spdx-license-ids": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", - "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", - "dev": true - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/stackframe": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", - "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==" + "node_modules/redux-promise-middleware": { + "version": "6.2.0", + "license": "MIT", + "peerDependencies": { + "redux": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0" + } }, - "node_modules/state-toggle": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz", - "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/redux-thunk": { + "version": "2.4.2", + "license": "MIT", + "peerDependencies": { + "redux": "^4" } }, - "node_modules/stop-iteration-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", - "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "node_modules/reflect-metadata": { + "version": "0.1.14", + "license": "Apache-2.0" + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.4", "dev": true, + "license": "MIT", "dependencies": { - "internal-slot": "^1.0.4" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/stream-browserify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", - "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", - "dev": true, - "dependencies": { - "inherits": "~2.0.4", - "readable-stream": "^3.5.0" - } + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "license": "MIT" }, - "node_modules/stream-browserify/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "node_modules/regexp.prototype.flags": { + "version": "1.5.1", "dev": true, + "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "set-function-name": "^2.0.0" }, "engines": { - "node": ">= 6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/stream-http": { + "node_modules/regexpp": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz", - "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==", "dev": true, - "dependencies": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "xtend": "^4.0.2" + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" } }, - "node_modules/stream-http/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "node_modules/rehype-highlight": { + "version": "7.0.0", "dev": true, + "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "@types/hast": "^3.0.0", + "hast-util-to-text": "^4.0.0", + "lowlight": "^3.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" }, - "engines": { - "node": ">= 6" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/remark-mdx": { + "version": "3.0.0", "dev": true, + "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.0" + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/string.prototype.matchall": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", - "integrity": "sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==", + "node_modules/remark-parse": { + "version": "11.0.0", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "regexp.prototype.flags": "^1.5.0", - "set-function-name": "^2.0.0", - "side-channel": "^1.0.4" + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "node_modules/remark-rehype": { + "version": "11.1.0", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "node_modules/remove-accents": { + "version": "0.5.0", + "license": "MIT" + }, + "node_modules/rename-keys": { + "version": "1.2.0", + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.8", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "node_modules/resolve-from": { + "version": "4.0.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pathname": { + "version": "3.0.0", + "license": "MIT" + }, + "node_modules/reusify": { + "version": "1.0.4", "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" } }, - "node_modules/stringify-entities": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.3.tgz", - "integrity": "sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g==", + "node_modules/rifm": { + "version": "0.12.1", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "license": "ISC", "dependencies": { - "character-entities-html4": "^2.0.0", - "character-entities-legacy": "^3.0.0" + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/stringify-entities/node_modules/character-entities-legacy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", - "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.11", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "license": "ISC", "dependencies": { - "ansi-regex": "^5.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, "engines": { - "node": ">=8" + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "license": "ISC", "dependencies": { - "min-indent": "^1.0.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=8" + "node": "*" } }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "node_modules/ripemd160": { + "version": "2.0.2", "dev": true, + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/rollup": { + "version": "4.9.6", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, "engines": { - "node": ">=8" + "node": ">=18.0.0", + "npm": ">=8.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.9.6", + "@rollup/rollup-android-arm64": "4.9.6", + "@rollup/rollup-darwin-arm64": "4.9.6", + "@rollup/rollup-darwin-x64": "4.9.6", + "@rollup/rollup-linux-arm-gnueabihf": "4.9.6", + "@rollup/rollup-linux-arm64-gnu": "4.9.6", + "@rollup/rollup-linux-arm64-musl": "4.9.6", + "@rollup/rollup-linux-riscv64-gnu": "4.9.6", + "@rollup/rollup-linux-x64-gnu": "4.9.6", + "@rollup/rollup-linux-x64-musl": "4.9.6", + "@rollup/rollup-win32-arm64-msvc": "4.9.6", + "@rollup/rollup-win32-ia32-msvc": "4.9.6", + "@rollup/rollup-win32-x64-msvc": "4.9.6", + "fsevents": "~2.3.2" } }, - "node_modules/style-to-object": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz", - "integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==", + "node_modules/run-parallel": { + "version": "1.2.0", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", "dependencies": { - "inline-style-parser": "0.1.1" + "queue-microtask": "^1.2.2" } }, - "node_modules/stylis": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", - "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/sade": { + "version": "1.8.1", + "license": "MIT", "dependencies": { - "has-flag": "^3.0.0" + "mri": "^1.1.0" }, "engines": { - "node": ">=4" + "node": ">=6" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "node_modules/safe-array-concat": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, "engines": { - "node": ">= 0.4" + "node": ">=0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/svg-parser": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", - "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", - "dev": true - }, - "node_modules/svgson": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/svgson/-/svgson-5.3.1.tgz", - "integrity": "sha512-qdPgvUNWb40gWktBJnbJRelWcPzkLed/ShhnRsjbayXz8OtdPOzbil9jtiZdrYvSDumAz/VNQr6JaNfPx/gvPA==", - "dependencies": { - "deep-rename-keys": "^0.2.1", - "xml-reader": "2.4.3" - } + "node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" }, - "node_modules/table": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", - "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", + "node_modules/safe-regex-test": { + "version": "1.0.2", "dev": true, + "license": "MIT", "dependencies": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", + "is-regex": "^1.1.4" }, "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "node": ">= 0.4" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/table/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/table/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/safer-buffer": { + "version": "2.1.2", "dev": true, + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.23.0", + "license": "MIT", + "peer": true, "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" + "loose-envify": "^1.1.0" } }, - "node_modules/terser": { - "version": "5.26.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.26.0.tgz", - "integrity": "sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==", - "optional": true, - "peer": true, + "node_modules/semver": { + "version": "7.5.4", + "dev": true, + "license": "ISC", "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" + "lru-cache": "^6.0.0" }, "bin": { - "terser": "bin/terser" + "semver": "bin/semver.js" }, "engines": { "node": ">=10" } }, - "node_modules/terser/node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "optional": true, - "peer": true, - "bin": { - "acorn": "bin/acorn" + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" }, "engines": { - "node": ">=0.4.0" + "node": ">=10" } }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "optional": true, - "peer": true + "node_modules/semver/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "node_modules/set-function-length": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.1", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.2", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } }, - "node_modules/timers-browserify": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", - "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "node_modules/set-function-name": { + "version": "2.0.1", "dev": true, + "license": "MIT", "dependencies": { - "setimmediate": "^1.0.4" + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" }, "engines": { - "node": ">=0.6.0" + "node": ">= 0.4" } }, - "node_modules/tiny-glob": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", - "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", + "node_modules/setimmediate": { + "version": "1.0.5", "dev": true, + "license": "MIT" + }, + "node_modules/sha.js": { + "version": "2.4.11", + "dev": true, + "license": "(MIT AND BSD-3-Clause)", "dependencies": { - "globalyzer": "0.1.0", - "globrex": "^0.1.2" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" } }, - "node_modules/tiny-invariant": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz", - "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==" - }, - "node_modules/tiny-warning": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", - "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" - }, - "node_modules/to-fast-properties": { + "node_modules/shebang-command": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, "engines": { - "node": ">=4" - } - }, - "node_modules/toggle-selection": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", - "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" - }, - "node_modules/toposort": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", - "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==" - }, - "node_modules/trim": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", - "integrity": "sha512-YzQV+TZg4AxpKxaTHK3c3D+kRDCGVEE7LemdlQZoQXn0iennk10RsIoY6ikzAqJTc9Xjl9C1/waHom/J86ziAQ==", - "deprecated": "Use String.prototype.trim() instead", - "dev": true - }, - "node_modules/trim-lines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", - "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node": ">=8" } }, - "node_modules/trim-newlines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", - "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "node_modules/shebang-regex": { + "version": "3.0.0", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/trim-trailing-lines": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz", - "integrity": "sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==", + "node_modules/side-channel": { + "version": "1.0.4", "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/trough": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", - "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==", + "node_modules/signal-exit": { + "version": "4.1.0", "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/ts-api-utils": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", - "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "node_modules/slash": { + "version": "3.0.0", "dev": true, + "license": "MIT", "engines": { - "node": ">=16.13.0" - }, - "peerDependencies": { - "typescript": ">=4.2.0" + "node": ">=8" } }, - "node_modules/ts-unused-exports": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/ts-unused-exports/-/ts-unused-exports-9.0.5.tgz", - "integrity": "sha512-1XAXaH2i4Al/aZO06pWDn9MUgTN0KQi+fvWudiWfHUTHAav45gzrx7Xq6JAsu6+LoMlVoyGvNvZSPW3KTjDncA==", + "node_modules/slice-ansi": { + "version": "4.0.0", "dev": true, + "license": "MIT", "dependencies": { - "chalk": "^4.0.0", - "tsconfig-paths": "^3.9.0" + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" }, - "bin": { - "ts-unused-exports": "bin/ts-unused-exports" + "engines": { + "node": ">=10" }, "funding": { - "url": "https://github.com/pzavolinsky/ts-unused-exports?sponsor=1" - }, - "peerDependencies": { - "typescript": ">=3.8.3" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": false - } + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/ts-unused-exports/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/snake-case": { + "version": "3.0.4", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/sockjs-client": { + "version": "1.6.1", + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "eventsource": "^2.0.2", + "faye-websocket": "^0.11.4", + "inherits": "^2.0.4", + "url-parse": "^1.5.10" }, "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://tidelift.com/funding/github/npm/sockjs-client" } }, - "node_modules/ts-unused-exports/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "node_modules/sockjs-client/node_modules/debug": { + "version": "3.2.7", + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "ms": "^2.1.1" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "license": "BSD-3-Clause", "engines": { - "node": ">=10" - }, + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "license": "MIT", "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/ts-unused-exports/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/spdx-correct": { + "version": "3.2.0", "dev": true, + "license": "Apache-2.0", "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" } }, - "node_modules/ts-unused-exports/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "node_modules/spdx-exceptions": { + "version": "2.4.0", + "dev": true, + "license": "CC-BY-3.0" }, - "node_modules/ts-unused-exports/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/spdx-expression-parse": { + "version": "3.0.1", "dev": true, - "engines": { - "node": ">=8" + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, - "node_modules/ts-unused-exports/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/spdx-license-ids": { + "version": "3.0.16", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "internal-slot": "^1.0.4" }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/tsconfck": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-2.1.2.tgz", - "integrity": "sha512-ghqN1b0puy3MhhviwO2kGF8SeMDNhEbnKxjK7h6+fvY9JAxqvXi8y5NAHSQv687OVboS2uZIByzGd45/YxrRHg==", + "node_modules/stream-browserify": { + "version": "3.0.0", "dev": true, - "bin": { - "tsconfck": "bin/tsconfck.js" - }, - "engines": { - "node": "^14.13.1 || ^16 || >=18" - }, - "peerDependencies": { - "typescript": "^4.3.5 || ^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "license": "MIT", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" } }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "node_modules/stream-http": { + "version": "3.2.0", "dev": true, + "license": "MIT", "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" } }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "node_modules/string_decoder": { + "version": "1.3.0", "dev": true, + "license": "MIT", "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" + "safe-buffer": "~5.2.0" } }, - "node_modules/tsconfig-paths/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "node_modules/string-width": { + "version": "5.1.2", "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, "engines": { - "node": ">=4" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" - }, - "node_modules/tty-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", - "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", "dev": true, + "license": "MIT", "dependencies": { - "prelude-ls": "^1.2.1" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">= 0.8.0" + "node": ">=8" } }, - "node_modules/type-fest": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", - "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", "dev": true, + "license": "MIT" + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/typed-array-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", - "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "is-typed-array": "^1.1.10" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">= 0.4" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/typed-array-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", - "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "node_modules/string.prototype.matchall": { + "version": "4.0.10", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "regexp.prototype.flags": "^1.5.0", + "set-function-name": "^2.0.0", + "side-channel": "^1.0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", - "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "node_modules/string.prototype.trim": { + "version": "1.2.8", "dev": true, + "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "engines": { "node": ">= 0.4" @@ -13692,1116 +10097,951 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "node_modules/string.prototype.trimend": { + "version": "1.0.7", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "node_modules/string.prototype.trimstart": { + "version": "1.0.7", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/undici": { - "version": "5.28.2", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.2.tgz", - "integrity": "sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w==", + "node_modules/stringify-entities": { + "version": "4.0.3", "dev": true, + "license": "MIT", "dependencies": { - "@fastify/busboy": "^2.0.0" + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" }, - "engines": { - "node": ">=14.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "devOptional": true - }, - "node_modules/unherit": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz", - "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==", + "node_modules/strip-ansi": { + "version": "6.0.1", "dev": true, + "license": "MIT", "dependencies": { - "inherits": "^2.0.0", - "xtend": "^4.0.0" + "ansi-regex": "^5.0.1" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "engines": { + "node": ">=8" } }, - "node_modules/unified": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz", - "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", "dev": true, + "license": "MIT", "dependencies": { - "bail": "^1.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^2.0.0", - "trough": "^1.0.0", - "vfile": "^4.0.0" + "ansi-regex": "^5.0.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=8" } }, - "node_modules/unified/node_modules/is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "node_modules/strip-bom": { + "version": "3.0.0", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], + "license": "MIT", "engines": { "node": ">=4" } }, - "node_modules/unified/node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "node_modules/strip-indent": { + "version": "3.0.0", "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, "engines": { "node": ">=8" } }, - "node_modules/unified/node_modules/unist-util-stringify-position": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", - "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", + "node_modules/strip-json-comments": { + "version": "3.1.1", "dev": true, - "dependencies": { - "@types/unist": "^2.0.2" + "license": "MIT", + "engines": { + "node": ">=8" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/unified/node_modules/vfile": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", - "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", - "dev": true, + "node_modules/style-to-object": { + "version": "0.4.4", + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^2.0.0", - "vfile-message": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "inline-style-parser": "0.1.1" } }, - "node_modules/unified/node_modules/vfile-message": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", - "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "node_modules/stylis": { + "version": "4.2.0", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "7.2.0", "dev": true, + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-stringify-position": "^2.0.0" + "has-flag": "^4.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=8" } }, - "node_modules/unist-builder": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-2.0.3.tgz", - "integrity": "sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw==", - "dev": true, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/unist-util-find-after": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", - "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", + "node_modules/svg-parser": { + "version": "2.0.4", "dev": true, + "license": "MIT" + }, + "node_modules/svgson": { + "version": "5.3.1", + "license": "MIT", "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "deep-rename-keys": "^0.2.1", + "xml-reader": "2.4.3" } }, - "node_modules/unist-util-find-after/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==", - "dev": true - }, - "node_modules/unist-util-find-after/node_modules/unist-util-is": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", - "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "node_modules/table": { + "version": "6.8.1", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@types/unist": "^3.0.0" + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=10.0.0" } }, - "node_modules/unist-util-generated": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.6.tgz", - "integrity": "sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg==", + "node_modules/table/node_modules/ajv": { + "version": "8.12.0", "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/unist-util-is": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", - "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", + "node_modules/table/node_modules/emoji-regex": { + "version": "8.0.0", "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } + "license": "MIT" }, - "node_modules/unist-util-position": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.1.0.tgz", - "integrity": "sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA==", + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } + "license": "MIT" }, - "node_modules/unist-util-position-from-estree": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", - "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", + "node_modules/table/node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "license": "MIT", "dependencies": { - "@types/unist": "^3.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=8" } }, - "node_modules/unist-util-position-from-estree/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "node_modules/text-table": { + "version": "0.2.0", + "dev": true, + "license": "MIT" }, - "node_modules/unist-util-remove": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-2.1.0.tgz", - "integrity": "sha512-J8NYPyBm4baYLdCbjmf1bhPu45Cr1MWTm77qd9istEkzWpnN6O9tMsEbB2JhNnBCqGENRqEWomQ+He6au0B27Q==", + "node_modules/timers-browserify": { + "version": "2.0.12", "dev": true, + "license": "MIT", "dependencies": { - "unist-util-is": "^4.0.0" + "setimmediate": "^1.0.4" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=0.6.0" } }, - "node_modules/unist-util-remove-position": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz", - "integrity": "sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==", + "node_modules/tiny-glob": { + "version": "0.2.9", "dev": true, + "license": "MIT", "dependencies": { - "unist-util-visit": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "globalyzer": "0.1.0", + "globrex": "^0.1.2" } }, - "node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } + "node_modules/tiny-invariant": { + "version": "1.3.1", + "license": "MIT" }, - "node_modules/unist-util-stringify-position/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "node_modules/tiny-warning": { + "version": "1.0.3", + "license": "MIT" }, - "node_modules/unist-util-visit": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", - "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", + "node_modules/to-fast-properties": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", "dev": true, + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^4.0.0", - "unist-util-visit-parents": "^3.0.0" + "is-number": "^7.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=8.0" } }, - "node_modules/unist-util-visit-parents": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", - "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", + "node_modules/toggle-selection": { + "version": "1.0.6", + "license": "MIT" + }, + "node_modules/toposort": { + "version": "2.0.2", + "license": "MIT" + }, + "node_modules/tr46": { + "version": "0.0.3", "dev": true, - "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^4.0.0" - }, + "license": "MIT" + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "license": "MIT", "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "node_modules/trim-newlines": { + "version": "3.0.1", "dev": true, + "license": "MIT", "engines": { - "node": ">= 10.0.0" + "node": ">=8" } }, - "node_modules/unload": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/unload/-/unload-2.2.0.tgz", - "integrity": "sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==", - "dependencies": { - "@babel/runtime": "^7.6.2", - "detect-node": "^2.0.4" + "node_modules/trough": { + "version": "2.1.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "update-browserslist-db": "cli.js" + "node_modules/ts-api-utils": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.13.0" }, "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/update-browserslist-db/node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" + "typescript": ">=4.2.0" } }, - "node_modules/url": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.3.tgz", - "integrity": "sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==", + "node_modules/ts-unused-exports": { + "version": "9.0.5", "dev": true, + "license": "MIT", "dependencies": { - "punycode": "^1.4.1", - "qs": "^6.11.2" - } - }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "node_modules/url/node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", - "dev": true - }, - "node_modules/use-context-selector": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/use-context-selector/-/use-context-selector-1.4.1.tgz", - "integrity": "sha512-Io2ArvcRO+6MWIhkdfMFt+WKQX+Vb++W8DS2l03z/Vw/rz3BclKpM0ynr4LYGyU85Eke+Yx5oIhTY++QR0ZDoA==", + "chalk": "^4.0.0", + "tsconfig-paths": "^3.9.0" + }, + "bin": { + "ts-unused-exports": "bin/ts-unused-exports" + }, + "funding": { + "url": "https://github.com/pzavolinsky/ts-unused-exports?sponsor=1" + }, "peerDependencies": { - "react": ">=16.8.0", - "react-dom": "*", - "react-native": "*", - "scheduler": ">=0.19.0" + "typescript": ">=3.8.3" }, "peerDependenciesMeta": { - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true + "typescript": { + "optional": false } } }, - "node_modules/use-debounce": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/use-debounce/-/use-debounce-10.0.0.tgz", - "integrity": "sha512-XRjvlvCB46bah9IBXVnq/ACP2lxqXyZj0D9hj4K5OzNroMDpTEBg8Anuh1/UfRTRs7pLhQ+RiNxxwZu9+MVl1A==", + "node_modules/tsconfck": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "bin": { + "tsconfck": "bin/tsconfck.js" + }, "engines": { - "node": ">= 16.0.0" + "node": "^18 || >=20" }, "peerDependencies": { - "react": ">=16.8.0" - } - }, - "node_modules/use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/util": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", - "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "node_modules/tsconfig-paths": { + "version": "3.15.0", "dev": true, + "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "which-typed-array": "^1.1.2" + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" } }, - "node_modules/util-deprecate": { + "node_modules/tsconfig-paths/node_modules/json5": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/uvu": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", - "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", + "dev": true, + "license": "MIT", "dependencies": { - "dequal": "^2.0.0", - "diff": "^5.0.0", - "kleur": "^4.0.3", - "sade": "^1.7.3" + "minimist": "^1.2.0" }, "bin": { - "uvu": "bin.js" - }, - "engines": { - "node": ">=8" + "json5": "lib/cli.js" } }, - "node_modules/v8-compile-cache": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", - "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", - "dev": true + "node_modules/tslib": { + "version": "2.6.2", + "license": "0BSD" }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "node_modules/tty-browserify": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/type-check": { + "version": "0.4.0", "dev": true, + "license": "MIT", "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/value-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", - "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" - }, - "node_modules/vfile": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", - "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0", - "vfile-message": "^4.0.0" + "node_modules/type-fest": { + "version": "0.18.1", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/vfile-location": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.2.0.tgz", - "integrity": "sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==", + "node_modules/typed-array-buffer": { + "version": "1.0.0", "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/vfile-message": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", - "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "dev": true, + "license": "MIT", "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0" + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/vfile-message/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, - "node_modules/vfile/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, - "node_modules/vite": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.10.tgz", - "integrity": "sha512-2P8J7WWgmc355HUMlFrwofacvr98DAjoE52BfdbwQtyLH06XKwaL/FMnmKM2crF0iX4MpmMKoDlNCB1ok7zHCw==", - "peer": true, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "dev": true, + "license": "MIT", "dependencies": { - "esbuild": "^0.19.3", - "postcss": "^8.4.32", - "rollup": "^4.2.0" - }, - "bin": { - "vite": "bin/vite.js" + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/vite-plugin-node-polyfills": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/vite-plugin-node-polyfills/-/vite-plugin-node-polyfills-0.19.0.tgz", - "integrity": "sha512-AhdVxAmVnd1doUlIRGUGV6ZRPfB9BvIwDF10oCOmL742IsvsFIAV4tSMxSfu5e0Px0QeJLgWVOSbtHIvblzqMw==", + "node_modules/typed-array-length": { + "version": "1.0.4", "dev": true, + "license": "MIT", "dependencies": { - "@rollup/plugin-inject": "^5.0.5", - "node-stdlib-browser": "^1.2.0" + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" }, "funding": { - "url": "https://github.com/sponsors/davidmyersdev" - }, - "peerDependencies": { - "vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/vite-plugin-static-copy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-1.0.0.tgz", - "integrity": "sha512-kMlrB3WDtC5GzFedNIPkpjnOAr8M11PfWOiUaONrUZ3AqogTsOmIhTt6w7Fh311wl8pN81ld7sfuOEogFJ9N8A==", + "node_modules/typescript": { + "version": "5.3.3", "dev": true, - "dependencies": { - "chokidar": "^3.5.3", - "fast-glob": "^3.2.11", - "fs-extra": "^11.1.0", - "picocolors": "^1.0.0" + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" }, "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "vite": "^5.0.0" + "node": ">=14.17" } }, - "node_modules/vite-plugin-static-copy/node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "node_modules/unbox-primitive": { + "version": "1.0.2", "dev": true, + "license": "MIT", "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" }, - "engines": { - "node": ">= 8" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/vite-plugin-static-copy/node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "node_modules/undici": { + "version": "5.28.2", "dev": true, + "license": "MIT", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, "engines": { - "node": ">=8" + "node": ">=14.0" } }, - "node_modules/vite-plugin-static-copy/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "node_modules/undici-types": { + "version": "5.26.5", + "devOptional": true, + "license": "MIT" + }, + "node_modules/unified": { + "version": "11.0.4", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" }, - "engines": { - "node": ">=8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite-plugin-static-copy/node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "node_modules/unified/node_modules/is-plain-obj": { + "version": "4.1.0", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, + "license": "MIT", "engines": { - "node": ">= 8.10.0" + "node": ">=12" }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/vite-plugin-static-copy/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "node_modules/unist-util-find-after": { + "version": "5.0.0", "dev": true, + "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" }, - "engines": { - "node": ">=8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite-plugin-static-copy/node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "node_modules/unist-util-generated": { + "version": "2.0.1", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.0", "dev": true, + "license": "MIT", "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "@types/unist": "^3.0.0" }, - "engines": { - "node": ">=14.14" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite-plugin-static-copy/node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "node_modules/unist-util-position": { + "version": "5.0.0", "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite-plugin-static-copy/node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "node_modules/unist-util-position-from-estree": { + "version": "2.0.0", "dev": true, + "license": "MIT", "dependencies": { - "binary-extensions": "^2.0.0" + "@types/unist": "^3.0.0" }, - "engines": { - "node": ">=8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite-plugin-static-copy/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/unist-util-remove-position": { + "version": "5.0.0", "dev": true, - "engines": { - "node": ">=0.12.0" + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite-plugin-static-copy/node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/vite-plugin-static-copy/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", "dev": true, + "license": "MIT", "dependencies": { - "picomatch": "^2.2.1" + "@types/unist": "^3.0.0" }, - "engines": { - "node": ">=8.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite-plugin-static-copy/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/unist-util-visit": { + "version": "5.0.0", "dev": true, + "license": "MIT", "dependencies": { - "is-number": "^7.0.0" + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" }, - "engines": { - "node": ">=8.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite-plugin-svgr": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/vite-plugin-svgr/-/vite-plugin-svgr-4.2.0.tgz", - "integrity": "sha512-SC7+FfVtNQk7So0XMjrrtLAbEC8qjFPifyD7+fs/E6aaNdVde6umlVVh0QuwDLdOMu7vp5RiGFsB70nj5yo0XA==", + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", "dev": true, + "license": "MIT", "dependencies": { - "@rollup/pluginutils": "^5.0.5", - "@svgr/core": "^8.1.0", - "@svgr/plugin-jsx": "^8.1.0" + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" }, - "peerDependencies": { - "vite": "^2.6.0 || 3 || 4 || 5" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite-plugin-svgr/node_modules/@svgr/babel-plugin-add-jsx-attribute": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", - "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", + "node_modules/universalify": { + "version": "2.0.1", "dev": true, + "license": "MIT", "engines": { - "node": ">=14" + "node": ">= 10.0.0" + } + }, + "node_modules/unload": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.6.2", + "detect-node": "^2.0.4" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "bin": { + "update-browserslist-db": "cli.js" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "browserslist": ">= 4.21.0" } }, - "node_modules/vite-plugin-svgr/node_modules/@svgr/babel-plugin-remove-jsx-attribute": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", - "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", + "node_modules/uri-js": { + "version": "4.4.1", "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" } }, - "node_modules/vite-plugin-svgr/node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", - "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", + "node_modules/url": { + "version": "0.11.3", "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "license": "MIT", + "dependencies": { + "punycode": "^1.4.1", + "qs": "^6.11.2" } }, - "node_modules/vite-plugin-svgr/node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", - "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", + "node_modules/url-parse": { + "version": "1.5.10", + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.4.1", "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, + "license": "MIT" + }, + "node_modules/use-context-selector": { + "version": "1.4.1", + "license": "MIT", "peerDependencies": { - "@babel/core": "^7.0.0-0" + "react": ">=16.8.0", + "react-dom": "*", + "react-native": "*", + "scheduler": ">=0.19.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } } }, - "node_modules/vite-plugin-svgr/node_modules/@svgr/babel-plugin-svg-dynamic-title": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", - "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", - "dev": true, + "node_modules/use-debounce": { + "version": "10.0.0", + "license": "MIT", "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "node": ">= 16.0.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "react": ">=16.8.0" } }, - "node_modules/vite-plugin-svgr/node_modules/@svgr/babel-plugin-svg-em-dimensions": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", - "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "license": "MIT", "peerDependencies": { - "@babel/core": "^7.0.0-0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, - "node_modules/vite-plugin-svgr/node_modules/@svgr/babel-plugin-transform-react-native-svg": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", - "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", + "node_modules/util": { + "version": "0.12.5", "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" } }, - "node_modules/vite-plugin-svgr/node_modules/@svgr/babel-plugin-transform-svg-component": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", - "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", + "node_modules/util-deprecate": { + "version": "1.0.2", "dev": true, - "engines": { - "node": ">=12" + "license": "MIT" + }, + "node_modules/uuid": { + "version": "9.0.0", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/uvu": { + "version": "0.5.6", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0", + "diff": "^5.0.0", + "kleur": "^4.0.3", + "sade": "^1.7.3" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "bin": { + "uvu": "bin.js" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=8" } }, - "node_modules/vite-plugin-svgr/node_modules/@svgr/babel-preset": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", - "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", + "node_modules/v8-compile-cache": { + "version": "2.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", - "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", - "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", - "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", - "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", - "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", - "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", - "@svgr/babel-plugin-transform-svg-component": "8.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" } }, - "node_modules/vite-plugin-svgr/node_modules/@svgr/core": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", - "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", + "node_modules/value-equal": { + "version": "1.0.1", + "license": "MIT" + }, + "node_modules/vfile": { + "version": "6.0.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/core": "^7.21.3", - "@svgr/babel-preset": "8.1.0", - "camelcase": "^6.2.0", - "cosmiconfig": "^8.1.3", - "snake-case": "^3.0.4" - }, - "engines": { - "node": ">=14" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite-plugin-svgr/node_modules/@svgr/hast-util-to-babel-ast": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", - "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", + "node_modules/vfile-message": { + "version": "4.0.2", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.21.3", - "entities": "^4.4.0" - }, - "engines": { - "node": ">=14" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite-plugin-svgr/node_modules/@svgr/plugin-jsx": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", - "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", - "dev": true, + "node_modules/victory-vendor": { + "version": "36.8.2", + "license": "MIT AND ISC", "dependencies": { - "@babel/core": "^7.21.3", - "@svgr/babel-preset": "8.1.0", - "@svgr/hast-util-to-babel-ast": "8.0.0", - "svg-parser": "^2.0.4" + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, + "node_modules/vite": { + "version": "5.0.12", + "license": "MIT", + "dependencies": { + "esbuild": "^0.19.3", + "postcss": "^8.4.32", + "rollup": "^4.2.0" + }, + "bin": { + "vite": "bin/vite.js" }, "engines": { - "node": ">=14" + "node": "^18.0.0 || >=20.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" }, "peerDependencies": { - "@svgr/core": "*" - } - }, - "node_modules/vite-plugin-svgr/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/vite-plugin-svgr/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } } }, - "node_modules/vite-plugin-svgr/node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "node_modules/vite-plugin-node-polyfills": { + "version": "0.19.0", "dev": true, + "license": "MIT", "dependencies": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" + "@rollup/plugin-inject": "^5.0.5", + "node-stdlib-browser": "^1.2.0" }, "funding": { - "url": "https://github.com/sponsors/d-fischer" + "url": "https://github.com/sponsors/davidmyersdev" }, "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0" } }, - "node_modules/vite-plugin-svgr/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "node_modules/vite-plugin-static-copy": { + "version": "1.0.1", "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.3", + "fast-glob": "^3.2.11", + "fs-extra": "^11.1.0", + "picocolors": "^1.0.0" + }, "engines": { - "node": ">=0.12" + "node": "^18.0.0 || >=20.0.0" }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "peerDependencies": { + "vite": "^5.0.0" } }, - "node_modules/vite-plugin-svgr/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "node_modules/vite-plugin-svgr": { + "version": "4.2.0", "dev": true, + "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "@rollup/pluginutils": "^5.0.5", + "@svgr/core": "^8.1.0", + "@svgr/plugin-jsx": "^8.1.0" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "peerDependencies": { + "vite": "^2.6.0 || 3 || 4 || 5" } }, "node_modules/vite-tsconfig-paths": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-4.2.3.tgz", - "integrity": "sha512-xVsA2xe6QSlzBujtWF8q2NYexh7PAUYfzJ4C8Axpe/7d2pcERYxuxGgph9F4f0iQO36g5tyGq6eBUYIssdUrVw==", + "version": "4.3.1", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.1.1", "globrex": "^0.1.2", - "tsconfck": "^2.1.0" + "tsconfck": "^3.0.1" }, "peerDependencies": { "vite": "*" @@ -14812,99 +11052,33 @@ } } }, - "node_modules/vite/node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/vite/node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "peer": true - }, - "node_modules/vite/node_modules/postcss": { - "version": "8.4.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", - "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "peer": true, - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, "node_modules/vm-browserify": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", - "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/vscode-oniguruma": { "version": "1.7.0", - "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", - "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/vscode-textmate": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", - "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", - "dev": true - }, - "node_modules/web-namespaces": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-1.1.4.tgz", - "integrity": "sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==", + "version": "9.0.0", "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", - "engines": { - "node": ">= 8" - } + "license": "MIT" }, "node_modules/web-vitals": { "version": "2.1.4", - "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-2.1.4.tgz", - "integrity": "sha512-sVWcwhU5mX6crfI5Vd2dC4qchyTqxV8URinzt25XqVh+bHEPGH4C3NPrNionCP7Obx59wrYEbNlw4Z8sjALzZg==" + "license": "Apache-2.0" + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/websocket-driver": { "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "license": "Apache-2.0", "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", @@ -14916,17 +11090,24 @@ }, "node_modules/websocket-extensions": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "license": "Apache-2.0", "engines": { "node": ">=0.8.0" } }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -14939,9 +11120,8 @@ }, "node_modules/which-boxed-primitive": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "dev": true, + "license": "MIT", "dependencies": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -14955,9 +11135,8 @@ }, "node_modules/which-builtin-type": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", - "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", "dev": true, + "license": "MIT", "dependencies": { "function.prototype.name": "^1.1.5", "has-tostringtag": "^1.0.0", @@ -14981,9 +11160,8 @@ }, "node_modules/which-collection": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", "dev": true, + "license": "MIT", "dependencies": { "is-map": "^2.0.1", "is-set": "^2.0.1", @@ -14996,9 +11174,8 @@ }, "node_modules/which-typed-array": { "version": "1.1.13", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", - "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", "dev": true, + "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.4", @@ -15013,28 +11190,111 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "license": "ISC" }, "node_modules/xml-lexer": { "version": "0.2.2", - "resolved": "https://registry.npmjs.org/xml-lexer/-/xml-lexer-0.2.2.tgz", - "integrity": "sha512-G0i98epIwiUEiKmMcavmVdhtymW+pCAohMRgybyIME9ygfVu8QheIi+YoQh3ngiThsT0SQzJT4R0sKDEv8Ou0w==", + "license": "MIT", "dependencies": { "eventemitter3": "^2.0.0" } }, "node_modules/xml-lexer/node_modules/eventemitter3": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz", - "integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==" + "license": "MIT" }, "node_modules/xml-reader": { "version": "2.4.3", - "resolved": "https://registry.npmjs.org/xml-reader/-/xml-reader-2.4.3.tgz", - "integrity": "sha512-xWldrIxjeAMAu6+HSf9t50ot1uL5M+BtOidRCWHXIeewvSeIpscWCsp4Zxjk8kHHhdqFBrfK8U0EJeCcnyQ/gA==", + "license": "MIT", "dependencies": { "eventemitter3": "^2.0.0", "xml-lexer": "^0.2.2" @@ -15042,14 +11302,12 @@ }, "node_modules/xml-reader/node_modules/eventemitter3": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz", - "integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==" + "license": "MIT" }, "node_modules/xstate": { "version": "4.38.3", - "resolved": "https://registry.npmjs.org/xstate/-/xstate-4.38.3.tgz", - "integrity": "sha512-SH7nAaaPQx57dx6qvfcIgqKRXIh4L0A1iYEqim4s1u7c9VoCgzZc+63FY90AKU4ZzOC2cfJzTnpO4zK7fCUzzw==", "dev": true, + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/xstate" @@ -15057,40 +11315,35 @@ }, "node_modules/xtend": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.4" } }, "node_modules/yallist": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + "license": "ISC" }, "node_modules/yaml": { "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", "engines": { "node": ">= 6" } }, "node_modules/yargs-parser": { "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/yauzl": { "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "dev": true, + "license": "MIT", "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" @@ -15098,9 +11351,8 @@ }, "node_modules/yocto-queue": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -15110,8 +11362,7 @@ }, "node_modules/yup": { "version": "0.32.11", - "resolved": "https://registry.npmjs.org/yup/-/yup-0.32.11.tgz", - "integrity": "sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.15.4", "@types/lodash": "^4.14.175", @@ -15127,8 +11378,7 @@ }, "node_modules/zustand": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.1.2.tgz", - "integrity": "sha512-gcRaKchcxFPbImrBb/BKgujOhHhik9YhVpIeP87ETT7uokEe2Szu7KkuZ9ghjtD+/KKkcrRNktR2AiLXPIbKIQ==", + "license": "MIT", "dependencies": { "use-sync-external-store": "1.2.0" }, @@ -15149,10 +11399,9 @@ } }, "node_modules/zwitch": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", - "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", + "version": "2.0.4", "dev": true, + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -15160,8 +11409,7 @@ }, "node_modules/zxcvbn": { "version": "4.4.2", - "resolved": "https://registry.npmjs.org/zxcvbn/-/zxcvbn-4.4.2.tgz", - "integrity": "sha512-Bq0B+ixT/DMyG8kgX2xWcI5jUvCwqrMxSFam7m0lAf78nf04hv6lNCsyLYdyYTrCVMqNDY/206K7eExYCeSyUQ==" + "license": "MIT" } } } diff --git a/webapp/package.json b/webapp/package.json index 7db49c5049..4a1662ddf6 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -10,16 +10,14 @@ "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", "@formatjs/icu-messageformat-parser": "^2.0.8", - "@mdx-js/rollup": "^3.0.0", "@mui/icons-material": "^5.5.1", "@mui/lab": "^5.0.0-alpha.75", "@mui/material": "^5.5.3", "@mui/x-date-pickers": "5.0.0-beta.6", - "@openreplay/tracker": "^3.5.4", "@sentry/browser": "^7.80.0", "@stomp/stompjs": "^6.1.2", "@tolgee/format-icu": "^5.16.0", - "@tolgee/react": "^5.16.0", + "@tolgee/react": "^5.19.3", "@vitejs/plugin-react": "^4.2.1", "clsx": "^1.1.1", "codemirror": "^5.62.0", @@ -29,14 +27,12 @@ "dotenv-flow": "4.0.1", "formik": "^2.2.9", "intl-messageformat": "^9.8.1", - "node-fetch": "3.3.0", "notistack": "^2.0.4", "posthog-js": "^1.96.1", - "prism-react-renderer": "1.2.1", - "prism-svelte": "0.4.7", + "prism-react-renderer": "^2.3.1", "react": "^17.0.1", "react-codemirror2": "^7.3.0", - "react-cropper": "2.1.8", + "react-cropper": "^2.3.3", "react-dnd": "^14.0.2", "react-dnd-html5-backend": "^14.0.0", "react-dom": "^17.0.2", @@ -50,7 +46,7 @@ "react-query": "^3.39.2", "react-redux": "^7.2.6", "react-router-dom": "^5.2.0", - "recharts": "2.1.9", + "recharts": "^2.11.0", "redux": "^4.1.0", "redux-promise-middleware": "^6.1.2", "redux-thunk": "^2.3.0", @@ -100,7 +96,7 @@ ] }, "devDependencies": { - "@mdx-js/loader": "1.6.22", + "@mdx-js/rollup": "^3.0.0", "@sentry/types": "^6.5.1", "@testing-library/jest-dom": "^5.14.1", "@testing-library/react": "^12.0.0", @@ -129,6 +125,7 @@ "rehype-highlight": "^7.0.0", "ts-unused-exports": "^9.0.4", "typescript": "^5.3.3", + "vite": "^5.0.12", "vite-plugin-node-polyfills": "^0.19.0", "vite-plugin-static-copy": "^1.0.0", "vite-plugin-svgr": "^4.2.0", diff --git a/webapp/src/custom.d.ts b/webapp/src/custom.d.ts index 3973c61a0e..2b4ac16230 100644 --- a/webapp/src/custom.d.ts +++ b/webapp/src/custom.d.ts @@ -1,4 +1,3 @@ -import API from '@openreplay/tracker'; import { PaletteColor } from '@mui/material/styles'; import { PaletteColorOptions } from '@mui/material'; import { @@ -73,9 +72,3 @@ declare module '@mui/material/Button' { default: true; } } - -declare global { - interface Window { - openReplayTracker?: API; - } -} diff --git a/webapp/vite.config.ts b/webapp/vite.config.ts index ebbd50e0e7..2939619e54 100644 --- a/webapp/vite.config.ts +++ b/webapp/vite.config.ts @@ -2,7 +2,6 @@ import { defineConfig, loadEnv } from 'vite'; import react from '@vitejs/plugin-react'; import viteTsconfigPaths from 'vite-tsconfig-paths'; import svgr from 'vite-plugin-svgr'; -import { nodePolyfills } from 'vite-plugin-node-polyfills'; import mdx from '@mdx-js/rollup'; import { viteStaticCopy } from 'vite-plugin-static-copy'; import { resolve } from 'path'; @@ -21,12 +20,16 @@ export default defineConfig(({ mode }) => { viteTsconfigPaths(), svgr(), mdx({ rehypePlugins: [rehypeHighlight] }), - nodePolyfills(), extractDataCy(), viteStaticCopy({ targets: [ { - src: resolve('node_modules/@tginternal/language-util/flags'), + src: resolve( + 'node_modules', + '@tginternal', + 'language-util', + 'flags' + ), dest: '', }, ], @@ -34,7 +37,7 @@ export default defineConfig(({ mode }) => { ], server: { // this ensures that the browser opens upon server start - open: true, + // open: true, // this sets a default port to 3000 port: Number(process.env.VITE_PORT) || 3000, }, From ac25e4942c91f095239b6c89ef0f557e90364384 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Mon, 5 Feb 2024 13:06:40 +0100 Subject: [PATCH 30/44] feat: add notification bell and root view --- e2e/cypress/support/dataCyType.d.ts | 2 + webapp/package-lock.json | 127 ++++++++++-------- webapp/package.json | 10 +- webapp/src/component/RootRouter.tsx | 10 +- .../layout/TopBar/NotificationBell.tsx | 62 +++++++++ webapp/src/component/layout/TopBar/TopBar.tsx | 10 +- webapp/src/constants/links.tsx | 6 + webapp/src/custom.d.ts | 7 + .../notifications/NotificationsRouter.tsx | 28 ++++ 9 files changed, 196 insertions(+), 66 deletions(-) create mode 100644 webapp/src/component/layout/TopBar/NotificationBell.tsx create mode 100644 webapp/src/views/notifications/NotificationsRouter.tsx diff --git a/e2e/cypress/support/dataCyType.d.ts b/e2e/cypress/support/dataCyType.d.ts index 999192f20f..8a9eb0a5a9 100644 --- a/e2e/cypress/support/dataCyType.d.ts +++ b/e2e/cypress/support/dataCyType.d.ts @@ -179,6 +179,8 @@ declare namespace DataCy { "global-list-pagination" | "global-list-search" | "global-loading" | + "global-notifications-button" | + "global-notifications-count" | "global-paginated-list" | "global-plus-button" | "global-search-field" | diff --git a/webapp/package-lock.json b/webapp/package-lock.json index b995fff888..b9e32cc47a 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -11,13 +11,13 @@ "@dicebear/avatars": "4.10.2", "@dicebear/avatars-identicon-sprites": "4.10.2", "@dicebear/avatars-initials-sprites": "4.10.2", - "@emotion/react": "^11.11.1", + "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", "@formatjs/icu-messageformat-parser": "^2.0.8", - "@mui/icons-material": "^5.5.1", - "@mui/lab": "^5.0.0-alpha.75", - "@mui/material": "^5.5.3", - "@mui/x-date-pickers": "5.0.0-beta.6", + "@mui/icons-material": "^5.15.7", + "@mui/lab": "^5.0.0-alpha.163", + "@mui/material": "^5.15.7", + "@mui/x-date-pickers": "^5.0.20", "@sentry/browser": "^7.80.0", "@stomp/stompjs": "^6.1.2", "@tolgee/format-icu": "^5.16.0", @@ -899,14 +899,16 @@ }, "node_modules/@floating-ui/core": { "version": "1.6.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.0.tgz", + "integrity": "sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==", "dependencies": { "@floating-ui/utils": "^0.2.1" } }, "node_modules/@floating-ui/dom": { "version": "1.6.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.1.tgz", + "integrity": "sha512-iA8qE43/H5iGozC3W0YSnVSW42Vh522yyM1gj+BqRwVsTNOyr231PsXDaV04yT39PsO0QL2QpbI/M0ZaLUQgRQ==", "dependencies": { "@floating-ui/core": "^1.6.0", "@floating-ui/utils": "^0.2.1" @@ -914,7 +916,8 @@ }, "node_modules/@floating-ui/react-dom": { "version": "2.0.8", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.8.tgz", + "integrity": "sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==", "dependencies": { "@floating-ui/dom": "^1.6.1" }, @@ -925,7 +928,8 @@ }, "node_modules/@floating-ui/utils": { "version": "0.2.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", + "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" }, "node_modules/@formatjs/ecma402-abstract": { "version": "1.18.2", @@ -1175,13 +1179,14 @@ } }, "node_modules/@mui/base": { - "version": "5.0.0-beta.33", - "license": "MIT", + "version": "5.0.0-beta.34", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.34.tgz", + "integrity": "sha512-e2mbTGTtReD/y5RFwnhkl1Tgl3XwgJhY040IlfkTVaU9f5LWrVhEnpRsYXu3B1CtLrwiWs4cu7aMHV9yRd4jpw==", "dependencies": { - "@babel/runtime": "^7.23.8", - "@floating-ui/react-dom": "^2.0.6", + "@babel/runtime": "^7.23.9", + "@floating-ui/react-dom": "^2.0.8", "@mui/types": "^7.2.13", - "@mui/utils": "^5.15.6", + "@mui/utils": "^5.15.7", "@popperjs/core": "^2.11.8", "clsx": "^2.1.0", "prop-types": "^15.8.1" @@ -1206,24 +1211,27 @@ }, "node_modules/@mui/base/node_modules/clsx": { "version": "2.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", "engines": { "node": ">=6" } }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.15.6", - "license": "MIT", + "version": "5.15.7", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.7.tgz", + "integrity": "sha512-AuF+Wo2Mp/edaO6vJnWjg+gj4tzEz5ChMZnAQpc22DXpSvM8ddgGcZvM7D7F99pIBoSv8ub+Iz0viL+yuGVmhg==", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" } }, "node_modules/@mui/icons-material": { - "version": "5.15.6", - "license": "MIT", + "version": "5.15.7", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.15.7.tgz", + "integrity": "sha512-EDAc8TVJGIA/imAvR3u4nANl2W5h3QeHieu2gK7Ypez/nIA55p08tHjf8UrMXEpxCAvfZO6piY9S9uaxETdicA==", "dependencies": { - "@babel/runtime": "^7.23.8" + "@babel/runtime": "^7.23.9" }, "engines": { "node": ">=12.0.0" @@ -1244,14 +1252,15 @@ } }, "node_modules/@mui/lab": { - "version": "5.0.0-alpha.162", - "license": "MIT", + "version": "5.0.0-alpha.163", + "resolved": "https://registry.npmjs.org/@mui/lab/-/lab-5.0.0-alpha.163.tgz", + "integrity": "sha512-ieOX3LFBln78jgNsBca0JUX+zAC2p6/u2P9b7rU9eZIr0AK44b5Qr8gDOWI1JfJtib4kxLGd1Msasrbxy5cMSQ==", "dependencies": { - "@babel/runtime": "^7.23.8", - "@mui/base": "5.0.0-beta.33", - "@mui/system": "^5.15.6", + "@babel/runtime": "^7.23.9", + "@mui/base": "5.0.0-beta.34", + "@mui/system": "^5.15.7", "@mui/types": "^7.2.13", - "@mui/utils": "^5.15.6", + "@mui/utils": "^5.15.7", "clsx": "^2.1.0", "prop-types": "^15.8.1" }, @@ -1290,16 +1299,16 @@ } }, "node_modules/@mui/material": { - "version": "5.15.6", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.6.tgz", - "integrity": "sha512-rw7bDdpi2kzfmcDN78lHp8swArJ5sBCKsn+4G3IpGfu44ycyWAWX0VdlvkjcR9Yrws2KIm7c+8niXpWHUDbWoA==", - "dependencies": { - "@babel/runtime": "^7.23.8", - "@mui/base": "5.0.0-beta.33", - "@mui/core-downloads-tracker": "^5.15.6", - "@mui/system": "^5.15.6", + "version": "5.15.7", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.7.tgz", + "integrity": "sha512-l6+AiKZH3iOJmZCnlpel8ghYQe9Lq0BEuKP8fGj3g5xz4arO9GydqYAtLPMvuHKtArj8lJGNuT2yHYxmejincA==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/base": "5.0.0-beta.34", + "@mui/core-downloads-tracker": "^5.15.7", + "@mui/system": "^5.15.7", "@mui/types": "^7.2.13", - "@mui/utils": "^5.15.6", + "@mui/utils": "^5.15.7", "@types/react-transition-group": "^4.4.10", "clsx": "^2.1.0", "csstype": "^3.1.2", @@ -1341,11 +1350,12 @@ } }, "node_modules/@mui/private-theming": { - "version": "5.15.6", - "license": "MIT", + "version": "5.15.7", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.7.tgz", + "integrity": "sha512-bcEeeXm7GyQCQvN9dwo8htGv8/6tP05p0i02Z7GXm5EoDPlBcqTNGugsjNLoGq6B0SsdyanjJGw0Jw00o1yAOA==", "dependencies": { - "@babel/runtime": "^7.23.8", - "@mui/utils": "^5.15.6", + "@babel/runtime": "^7.23.9", + "@mui/utils": "^5.15.7", "prop-types": "^15.8.1" }, "engines": { @@ -1366,10 +1376,11 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.15.6", - "license": "MIT", + "version": "5.15.7", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.15.7.tgz", + "integrity": "sha512-ixSdslOjK1kzdGcxqj7O3d14By/LPQ7EWknsViQ8RaeT863EAQemS+zvUJDTcOpkfJh6q6gPnYMIb2TJCs9eWA==", "dependencies": { - "@babel/runtime": "^7.23.8", + "@babel/runtime": "^7.23.9", "@emotion/cache": "^11.11.0", "csstype": "^3.1.2", "prop-types": "^15.8.1" @@ -1396,14 +1407,15 @@ } }, "node_modules/@mui/system": { - "version": "5.15.6", - "license": "MIT", + "version": "5.15.7", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.7.tgz", + "integrity": "sha512-9alZ4/dLxsTwUOdqakgzxiL5YW6ntqj0CfzWImgWnBMTZhgGcPsbYpBLniNkkk7/jptma4/bykWXHwju/ls/pg==", "dependencies": { - "@babel/runtime": "^7.23.8", - "@mui/private-theming": "^5.15.6", - "@mui/styled-engine": "^5.15.6", + "@babel/runtime": "^7.23.9", + "@mui/private-theming": "^5.15.7", + "@mui/styled-engine": "^5.15.7", "@mui/types": "^7.2.13", - "@mui/utils": "^5.15.6", + "@mui/utils": "^5.15.7", "clsx": "^2.1.0", "csstype": "^3.1.2", "prop-types": "^15.8.1" @@ -1453,10 +1465,11 @@ } }, "node_modules/@mui/utils": { - "version": "5.15.6", - "license": "MIT", + "version": "5.15.7", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.7.tgz", + "integrity": "sha512-8qhsxQRNV6aEOjjSk6YQIYJxkF5klhj8oG1FEEU4z6HV78TjNqRxMP08QGcdsibEbez+nihAaz6vu83b4XqbAg==", "dependencies": { - "@babel/runtime": "^7.23.8", + "@babel/runtime": "^7.23.9", "@types/prop-types": "^15.7.11", "prop-types": "^15.8.1", "react-is": "^18.2.0" @@ -1479,16 +1492,17 @@ } }, "node_modules/@mui/x-date-pickers": { - "version": "5.0.0-beta.6", - "license": "MIT", + "version": "5.0.20", + "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-5.0.20.tgz", + "integrity": "sha512-ERukSeHIoNLbI1C2XRhF9wRhqfsr+Q4B1SAw2ZlU7CWgcG8UBOxgqRKDEOVAIoSWL+DWT6GRuQjOKvj6UXZceA==", "dependencies": { - "@babel/runtime": "^7.18.6", + "@babel/runtime": "^7.18.9", "@date-io/core": "^2.15.0", "@date-io/date-fns": "^2.15.0", "@date-io/dayjs": "^2.15.0", "@date-io/luxon": "^2.15.0", "@date-io/moment": "^2.15.0", - "@mui/utils": "^5.4.1", + "@mui/utils": "^5.10.3", "@types/react-transition-group": "^4.4.5", "clsx": "^1.2.1", "prop-types": "^15.7.2", @@ -1578,7 +1592,8 @@ }, "node_modules/@popperjs/core": { "version": "2.11.8", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" diff --git a/webapp/package.json b/webapp/package.json index 4a1662ddf6..0600293f33 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -7,13 +7,13 @@ "@dicebear/avatars": "4.10.2", "@dicebear/avatars-identicon-sprites": "4.10.2", "@dicebear/avatars-initials-sprites": "4.10.2", - "@emotion/react": "^11.11.1", + "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", "@formatjs/icu-messageformat-parser": "^2.0.8", - "@mui/icons-material": "^5.5.1", - "@mui/lab": "^5.0.0-alpha.75", - "@mui/material": "^5.5.3", - "@mui/x-date-pickers": "5.0.0-beta.6", + "@mui/icons-material": "^5.15.7", + "@mui/lab": "^5.0.0-alpha.163", + "@mui/material": "^5.15.7", + "@mui/x-date-pickers": "^5.0.20", "@sentry/browser": "^7.80.0", "@stomp/stompjs": "^6.1.2", "@tolgee/format-icu": "^5.16.0", diff --git a/webapp/src/component/RootRouter.tsx b/webapp/src/component/RootRouter.tsx index fc42cd99f0..b8f75553eb 100644 --- a/webapp/src/component/RootRouter.tsx +++ b/webapp/src/component/RootRouter.tsx @@ -1,6 +1,7 @@ import { Redirect, Route, Switch } from 'react-router-dom'; import { LINKS } from 'tg.constants/links'; import { PrivateRoute } from './common/PrivateRoute'; +import { NotificationsRouter } from 'tg.views/notifications/NotificationsRouter'; import { ProjectsRouter } from 'tg.views/projects/ProjectsRouter'; import { UserSettingsRouter } from 'tg.views/userSettings/UserSettingsRouter'; import { OrganizationsRouter } from 'tg.views/organizations/OrganizationsRouter'; @@ -81,9 +82,12 @@ export const RootRouter = () => ( - - - + + + + + + diff --git a/webapp/src/component/layout/TopBar/NotificationBell.tsx b/webapp/src/component/layout/TopBar/NotificationBell.tsx new file mode 100644 index 0000000000..2d4ef63b38 --- /dev/null +++ b/webapp/src/component/layout/TopBar/NotificationBell.tsx @@ -0,0 +1,62 @@ +/** + * Copyright (C) 2024 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { Box, IconButton, styled } from '@mui/material'; +import { Notifications } from '@mui/icons-material'; +import { Link } from 'react-router-dom'; +import { LINKS } from 'tg.constants/links'; + +const StyledIconButton = styled(IconButton)` + width: 40px; + height: 40px; + position: relative; +`; + +const StyledNotificationCount = styled(Box)` + border: 3px ${({ theme }) => theme.palette.navbar.background} solid; + border-radius: 0.6rem; + background-color: ${({ theme }) => theme.palette.error.main}; + color: ${({ theme }) => theme.palette.error.contrastText}; + height: 1.2rem; + min-width: 1.2rem; + padding: 0 2px; + font-size: 0.6rem; + font-weight: bold; + display: flex; + align-items: center; + justify-content: center; + position: absolute; + bottom: 0.2rem; + right: 0.2rem; +`; + +export const NotificationBell: React.FC = () => { + return ( + + + + 1 + + + ); +}; diff --git a/webapp/src/component/layout/TopBar/TopBar.tsx b/webapp/src/component/layout/TopBar/TopBar.tsx index b493c3db2d..ee57d0f507 100644 --- a/webapp/src/component/layout/TopBar/TopBar.tsx +++ b/webapp/src/component/layout/TopBar/TopBar.tsx @@ -1,3 +1,4 @@ +import { useSelector } from 'react-redux'; import { Link } from 'react-router-dom'; import { Box, styled, useTheme } from '@mui/material'; import AppBar from '@mui/material/AppBar'; @@ -13,7 +14,7 @@ import { AdminInfo } from './AdminInfo'; import { QuickStartTopBarButton } from '../QuickStartGuide/QuickStartTopBarButton'; import { LanguageMenu } from 'tg.component/layout/TopBar/LanguageMenu'; import { AppState } from 'tg.store/index'; -import { useSelector } from 'react-redux'; +import { NotificationBell } from 'tg.component/layout/TopBar/NotificationBell'; export const TOP_BAR_HEIGHT = 52; @@ -125,7 +126,12 @@ export const TopBar: React.FC = ({ {!userLogged && } - {userLogged && } + {userLogged && ( + <> + + + + )} ); diff --git a/webapp/src/constants/links.tsx b/webapp/src/constants/links.tsx index d4b61e52af..0a29bd9287 100644 --- a/webapp/src/constants/links.tsx +++ b/webapp/src/constants/links.tsx @@ -158,6 +158,12 @@ export class LINKS { 'disable-mfa' ); + /** + * Notifications + */ + + static NOTIFICATIONS = Link.ofRoot('notifications'); + /** * Administration */ diff --git a/webapp/src/custom.d.ts b/webapp/src/custom.d.ts index 2b4ac16230..932fe15b5f 100644 --- a/webapp/src/custom.d.ts +++ b/webapp/src/custom.d.ts @@ -20,6 +20,7 @@ declare module '*.svg' { export default content; } import { colors } from './colors'; +import { ComponentType, ElementType } from 'react' const all = { ...colors.light, ...colors.dark }; @@ -72,3 +73,9 @@ declare module '@mui/material/Button' { default: true; } } + +declare module '@mui/material/ButtonBase' { + interface ButtonBaseOwnProps> extends TProps { + component?: T; + } +} diff --git a/webapp/src/views/notifications/NotificationsRouter.tsx b/webapp/src/views/notifications/NotificationsRouter.tsx new file mode 100644 index 0000000000..cb5fa84719 --- /dev/null +++ b/webapp/src/views/notifications/NotificationsRouter.tsx @@ -0,0 +1,28 @@ +/** + * Copyright (C) 2024 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react' +import { Switch } from 'react-router-dom' +import { DashboardPage } from 'tg.component/layout/DashboardPage' + +export const NotificationsRouter: React.FC = () => { + return ( + + + + + ) +} From ca62a126acfee592de1726597a431c81c77a47b8 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Mon, 5 Feb 2024 19:39:10 +0100 Subject: [PATCH 31/44] fix: workaround the fact npm is a bad pkg manager --- webapp/package-lock.json | 4561 +++++++++-------- webapp/package.json | 21 +- webapp/src/component/RootRouter.tsx | 38 +- .../common/avatar/useAutoAvatarImgSrc.tsx | 68 +- webapp/src/custom.d.ts | 6 +- webapp/src/store/index.ts | 2 +- .../notifications/NotificationsRouter.tsx | 19 +- 7 files changed, 2530 insertions(+), 2185 deletions(-) diff --git a/webapp/package-lock.json b/webapp/package-lock.json index b9e32cc47a..be2ec1e012 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -8,9 +8,9 @@ "name": "webapp", "version": "0.1.0", "dependencies": { - "@dicebear/avatars": "4.10.2", - "@dicebear/avatars-identicon-sprites": "4.10.2", - "@dicebear/avatars-initials-sprites": "4.10.2", + "@dicebear/core": "^7.0.4", + "@dicebear/identicon": "^7.0.4", + "@dicebear/initials": "^7.0.4", "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", "@formatjs/icu-messageformat-parser": "^2.0.8", @@ -37,8 +37,6 @@ "react": "^17.0.1", "react-codemirror2": "^7.3.0", "react-cropper": "^2.3.3", - "react-dnd": "^14.0.2", - "react-dnd-html5-backend": "^14.0.0", "react-dom": "^17.0.2", "react-draggable": "^4.4.3", "react-google-recaptcha-v3": "1.9.5", @@ -67,12 +65,13 @@ }, "devDependencies": { "@mdx-js/rollup": "^3.0.0", + "@redux-devtools/extension": "^3.3.0", "@sentry/types": "^6.5.1", "@testing-library/jest-dom": "^5.14.1", "@testing-library/react": "^12.0.0", "@testing-library/user-event": "^13.2.1", "@tginternal/language-util": "^1.0.6", - "@tolgee/cli": "^1.0.1", + "@tolgee/cli": "^1.3.2", "@types/codemirror": "^5.60.2", "@types/diff": "^5.0.2", "@types/jest": "^26.0.24", @@ -91,12 +90,10 @@ "eslint-plugin-react": "^7.24.0", "openapi-typescript": "^4.0.2", "prettier": "^2.3.1", - "redux-devtools-extension": "^2.13.9", "rehype-highlight": "^7.0.0", "ts-unused-exports": "^9.0.4", "typescript": "^5.3.3", "vite": "^5.0.12", - "vite-plugin-node-polyfills": "^0.19.0", "vite-plugin-static-copy": "^1.0.0", "vite-plugin-svgr": "^4.2.0", "vite-tsconfig-paths": "^4.2.3" @@ -104,20 +101,23 @@ }, "node_modules/@aashutoshrathi/word-wrap": { "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/@adobe/css-tools": { "version": "4.3.3", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.3.tgz", + "integrity": "sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ==", + "dev": true }, "node_modules/@ampproject/remapping": { "version": "2.2.1", - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", "dependencies": { "@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -128,7 +128,8 @@ }, "node_modules/@babel/code-frame": { "version": "7.23.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", "dependencies": { "@babel/highlight": "^7.23.4", "chalk": "^2.4.2" @@ -139,7 +140,8 @@ }, "node_modules/@babel/code-frame/node_modules/ansi-styles": { "version": "3.2.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dependencies": { "color-convert": "^1.9.0" }, @@ -149,7 +151,8 @@ }, "node_modules/@babel/code-frame/node_modules/chalk": { "version": "2.4.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -161,32 +164,37 @@ }, "node_modules/@babel/code-frame/node_modules/color-convert": { "version": "1.9.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dependencies": { "color-name": "1.1.3" } }, "node_modules/@babel/code-frame/node_modules/color-name": { "version": "1.1.3", - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { "version": "1.0.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "engines": { "node": ">=0.8.0" } }, "node_modules/@babel/code-frame/node_modules/has-flag": { "version": "3.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "engines": { "node": ">=4" } }, "node_modules/@babel/code-frame/node_modules/supports-color": { "version": "5.5.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dependencies": { "has-flag": "^3.0.0" }, @@ -196,14 +204,16 @@ }, "node_modules/@babel/compat-data": { "version": "7.23.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { "version": "7.23.9", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", + "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.23.5", @@ -231,18 +241,21 @@ }, "node_modules/@babel/core/node_modules/convert-source-map": { "version": "2.0.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", - "license": "ISC", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/generator": { "version": "7.23.6", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", "dependencies": { "@babel/types": "^7.23.6", "@jridgewell/gen-mapping": "^0.3.2", @@ -255,7 +268,8 @@ }, "node_modules/@babel/helper-compilation-targets": { "version": "7.23.6", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", "dependencies": { "@babel/compat-data": "^7.23.5", "@babel/helper-validator-option": "^7.23.5", @@ -269,21 +283,24 @@ }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", - "license": "ISC", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/helper-environment-visitor": { "version": "7.22.20", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { "version": "7.23.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dependencies": { "@babel/template": "^7.22.15", "@babel/types": "^7.23.0" @@ -294,7 +311,8 @@ }, "node_modules/@babel/helper-hoist-variables": { "version": "7.22.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dependencies": { "@babel/types": "^7.22.5" }, @@ -304,7 +322,8 @@ }, "node_modules/@babel/helper-module-imports": { "version": "7.22.15", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", "dependencies": { "@babel/types": "^7.22.15" }, @@ -314,7 +333,8 @@ }, "node_modules/@babel/helper-module-transforms": { "version": "7.23.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-module-imports": "^7.22.15", @@ -331,14 +351,16 @@ }, "node_modules/@babel/helper-plugin-utils": { "version": "7.22.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { "version": "7.22.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", "dependencies": { "@babel/types": "^7.22.5" }, @@ -348,7 +370,8 @@ }, "node_modules/@babel/helper-split-export-declaration": { "version": "7.22.6", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dependencies": { "@babel/types": "^7.22.5" }, @@ -358,28 +381,32 @@ }, "node_modules/@babel/helper-string-parser": { "version": "7.23.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { "version": "7.22.20", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { "version": "7.23.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { "version": "7.23.9", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.9.tgz", + "integrity": "sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==", "dependencies": { "@babel/template": "^7.23.9", "@babel/traverse": "^7.23.9", @@ -391,7 +418,8 @@ }, "node_modules/@babel/highlight": { "version": "7.23.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", @@ -403,7 +431,8 @@ }, "node_modules/@babel/highlight/node_modules/ansi-styles": { "version": "3.2.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dependencies": { "color-convert": "^1.9.0" }, @@ -413,7 +442,8 @@ }, "node_modules/@babel/highlight/node_modules/chalk": { "version": "2.4.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -425,32 +455,37 @@ }, "node_modules/@babel/highlight/node_modules/color-convert": { "version": "1.9.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dependencies": { "color-name": "1.1.3" } }, "node_modules/@babel/highlight/node_modules/color-name": { "version": "1.1.3", - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/@babel/highlight/node_modules/escape-string-regexp": { "version": "1.0.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "engines": { "node": ">=0.8.0" } }, "node_modules/@babel/highlight/node_modules/has-flag": { "version": "3.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "engines": { "node": ">=4" } }, "node_modules/@babel/highlight/node_modules/supports-color": { "version": "5.5.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dependencies": { "has-flag": "^3.0.0" }, @@ -460,7 +495,8 @@ }, "node_modules/@babel/parser": { "version": "7.23.9", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz", + "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==", "bin": { "parser": "bin/babel-parser.js" }, @@ -470,7 +506,8 @@ }, "node_modules/@babel/plugin-transform-react-jsx-self": { "version": "7.23.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz", + "integrity": "sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, @@ -483,7 +520,8 @@ }, "node_modules/@babel/plugin-transform-react-jsx-source": { "version": "7.23.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz", + "integrity": "sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, @@ -496,7 +534,8 @@ }, "node_modules/@babel/runtime": { "version": "7.23.9", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -506,11 +545,13 @@ }, "node_modules/@babel/runtime/node_modules/regenerator-runtime": { "version": "0.14.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, "node_modules/@babel/template": { "version": "7.23.9", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz", + "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==", "dependencies": { "@babel/code-frame": "^7.23.5", "@babel/parser": "^7.23.9", @@ -522,7 +563,8 @@ }, "node_modules/@babel/traverse": { "version": "7.23.9", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz", + "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==", "dependencies": { "@babel/code-frame": "^7.23.5", "@babel/generator": "^7.23.6", @@ -541,7 +583,8 @@ }, "node_modules/@babel/types": { "version": "7.23.9", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz", + "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==", "dependencies": { "@babel/helper-string-parser": "^7.23.4", "@babel/helper-validator-identifier": "^7.22.20", @@ -553,11 +596,13 @@ }, "node_modules/@date-io/core": { "version": "2.17.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@date-io/core/-/core-2.17.0.tgz", + "integrity": "sha512-+EQE8xZhRM/hsY0CDTVyayMDDY5ihc4MqXCrPxooKw19yAzUIC6uUqsZeaOFNL9YKTNxYKrJP5DFgE8o5xRCOw==" }, "node_modules/@date-io/date-fns": { "version": "2.17.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@date-io/date-fns/-/date-fns-2.17.0.tgz", + "integrity": "sha512-L0hWZ/mTpy3Gx/xXJ5tq5CzHo0L7ry6KEO9/w/JWiFWFLZgiNVo3ex92gOl3zmzjHqY/3Ev+5sehAr8UnGLEng==", "dependencies": { "@date-io/core": "^2.17.0" }, @@ -572,7 +617,8 @@ }, "node_modules/@date-io/dayjs": { "version": "2.17.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@date-io/dayjs/-/dayjs-2.17.0.tgz", + "integrity": "sha512-Iq1wjY5XzBh0lheFA0it6Dsyv94e8mTiNR8vuTai+KopxDkreL3YjwTmZHxkgB7/vd0RMIACStzVgWvPATnDCA==", "dependencies": { "@date-io/core": "^2.17.0" }, @@ -587,7 +633,8 @@ }, "node_modules/@date-io/luxon": { "version": "2.17.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@date-io/luxon/-/luxon-2.17.0.tgz", + "integrity": "sha512-l712Vdm/uTddD2XWt9TlQloZUiTiRQtY5TCOG45MQ/8u0tu8M17BD6QYHar/3OrnkGybALAMPzCy1r5D7+0HBg==", "dependencies": { "@date-io/core": "^2.17.0" }, @@ -602,7 +649,8 @@ }, "node_modules/@date-io/moment": { "version": "2.17.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@date-io/moment/-/moment-2.17.0.tgz", + "integrity": "sha512-e4nb4CDZU4k0WRVhz1Wvl7d+hFsedObSauDHKtZwU9kt7gdYEAzKgnrSCTHsEaXrDumdrkCYTeZ0Tmyk7uV4tw==", "dependencies": { "@date-io/core": "^2.17.0" }, @@ -615,35 +663,72 @@ } } }, - "node_modules/@dicebear/avatars": { - "version": "4.10.2", - "license": "MIT", + "node_modules/@dicebear/converter": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@dicebear/converter/-/converter-7.0.4.tgz", + "integrity": "sha512-oiA2Oc5izWf6ipPtHYCi2c9W565VzyryObtSL6xB36V9MHRD8wvH5mYr9AvbViDGEOOeNE3EtIELQIMdNtB7Rg==", + "dependencies": { + "@types/json-schema": "^7.0.11", + "tmp-promise": "^3.0.3" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@resvg/resvg-js": "^2.4.1", + "exiftool-vendored": "^23.0.0", + "sharp": "^0.32.6" + }, + "peerDependenciesMeta": { + "@resvg/resvg-js": { + "optional": true + }, + "exiftool-vendored": { + "optional": true + }, + "sharp": { + "optional": true + } + } + }, + "node_modules/@dicebear/core": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@dicebear/core/-/core-7.0.4.tgz", + "integrity": "sha512-Xi8Au8K4pWj61jKMKqlhqmg83DvMAG6PfDuDbp7F75ZNvrGGh0BkJt9keSHe4WpHs+BbXDXSMOivSS10QB20fA==", "dependencies": { - "@types/json-schema": "^7.0.7", - "pure-color": "^1.3.0", - "svgson": "^5.2.1" + "@dicebear/converter": "7.0.4", + "@types/json-schema": "^7.0.11" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@dicebear/avatars-identicon-sprites": { - "version": "4.10.2", - "license": "MIT", + "node_modules/@dicebear/identicon": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@dicebear/identicon/-/identicon-7.0.4.tgz", + "integrity": "sha512-Q68lP7dqqt0fMx9SONPJSi94aieNveTyrCgv/kuU3F9upeQyesmdAeQ+e2QOojOOMrEuM+ujFuPInvwwkaZF7w==", + "engines": { + "node": ">=16.0.0" + }, "peerDependencies": { - "@dicebear/avatars": "^4.6.0" + "@dicebear/core": "^7.0.0" } }, - "node_modules/@dicebear/avatars-initials-sprites": { - "version": "4.10.2", - "license": "MIT", - "dependencies": { - "initials": "^3.0.1" + "node_modules/@dicebear/initials": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@dicebear/initials/-/initials-7.0.4.tgz", + "integrity": "sha512-cNkuG/3cPbF4UScmLk+2nYF2LaB9N1k3Pw1gmd3PST+oUsdlkNIM6e4Wym/0fgDLGPWyxbiGsbhe371ACWJVNQ==", + "engines": { + "node": ">=16.0.0" }, "peerDependencies": { - "@dicebear/avatars": "^4.6.0" + "@dicebear/core": "^7.0.0" } }, "node_modules/@emotion/babel-plugin": { "version": "11.11.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", + "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/runtime": "^7.18.3", @@ -660,7 +745,8 @@ }, "node_modules/@emotion/cache": { "version": "11.11.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", "dependencies": { "@emotion/memoize": "^0.8.1", "@emotion/sheet": "^1.2.2", @@ -671,22 +757,26 @@ }, "node_modules/@emotion/hash": { "version": "0.9.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", + "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" }, "node_modules/@emotion/is-prop-valid": { "version": "1.2.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz", + "integrity": "sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==", "dependencies": { "@emotion/memoize": "^0.8.1" } }, "node_modules/@emotion/memoize": { "version": "0.8.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" }, "node_modules/@emotion/react": { "version": "11.11.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.3.tgz", + "integrity": "sha512-Cnn0kuq4DoONOMcnoVsTOR8E+AdnKFf//6kUWc4LCdnxj31pZWn7rIULd6Y7/Js1PiPHzn7SKCM9vB/jBni8eA==", "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.11.0", @@ -708,7 +798,8 @@ }, "node_modules/@emotion/serialize": { "version": "1.1.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.3.tgz", + "integrity": "sha512-iD4D6QVZFDhcbH0RAG1uVu1CwVLMWUkCvAqqlewO/rxf8+87yIBAlt4+AxMiiKPLs5hFc0owNk/sLLAOROw3cA==", "dependencies": { "@emotion/hash": "^0.9.1", "@emotion/memoize": "^0.8.1", @@ -719,11 +810,13 @@ }, "node_modules/@emotion/sheet": { "version": "1.2.2", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", + "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" }, "node_modules/@emotion/styled": { "version": "11.11.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.0.tgz", + "integrity": "sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==", "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.11.0", @@ -744,29 +837,364 @@ }, "node_modules/@emotion/unitless": { "version": "0.8.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" }, "node_modules/@emotion/use-insertion-effect-with-fallbacks": { "version": "1.0.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", + "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", "peerDependencies": { "react": ">=16.8.0" } }, "node_modules/@emotion/utils": { "version": "1.2.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" }, "node_modules/@emotion/weak-memoize": { "version": "0.3.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } }, "node_modules/@esbuild/win32-x64": { "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "win32" @@ -777,8 +1205,9 @@ }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, - "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.3.0" }, @@ -791,16 +1220,18 @@ }, "node_modules/@eslint-community/regexpp": { "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", "dev": true, - "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", "dev": true, - "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.1.1", @@ -818,16 +1249,18 @@ }, "node_modules/@eslint/eslintrc/node_modules/argparse": { "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, - "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" } }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -835,8 +1268,9 @@ }, "node_modules/@eslint/eslintrc/node_modules/globals": { "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, - "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -849,16 +1283,18 @@ }, "node_modules/@eslint/eslintrc/node_modules/ignore": { "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/@eslint/eslintrc/node_modules/js-yaml": { "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, - "license": "MIT", "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -869,8 +1305,9 @@ }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -880,8 +1317,9 @@ }, "node_modules/@eslint/eslintrc/node_modules/type-fest": { "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, - "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -891,8 +1329,9 @@ }, "node_modules/@fastify/busboy": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", + "integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==", "dev": true, - "license": "MIT", "engines": { "node": ">=14" } @@ -933,7 +1372,8 @@ }, "node_modules/@formatjs/ecma402-abstract": { "version": "1.18.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.18.2.tgz", + "integrity": "sha512-+QoPW4csYALsQIl8GbN14igZzDbuwzcpWrku9nyMXlaqAlwRBgl5V+p0vWMGFqHOw37czNXaP/lEk4wbLgcmtA==", "dependencies": { "@formatjs/intl-localematcher": "0.5.4", "tslib": "^2.4.0" @@ -941,14 +1381,16 @@ }, "node_modules/@formatjs/fast-memoize": { "version": "1.2.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-1.2.1.tgz", + "integrity": "sha512-Rg0e76nomkz3vF9IPlKeV+Qynok0r7YZjL6syLz4/urSg0IbjPZCB/iYUMNsYA643gh4mgrX3T7KEIFIxJBQeg==", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@formatjs/icu-messageformat-parser": { "version": "2.7.6", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.6.tgz", + "integrity": "sha512-etVau26po9+eewJKYoiBKP6743I1br0/Ie00Pb/S/PtmYfmjTcOn2YCh2yNkSZI12h6Rg+BOgQYborXk46BvkA==", "dependencies": { "@formatjs/ecma402-abstract": "1.18.2", "@formatjs/icu-skeleton-parser": "1.8.0", @@ -957,7 +1399,8 @@ }, "node_modules/@formatjs/icu-skeleton-parser": { "version": "1.8.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.0.tgz", + "integrity": "sha512-QWLAYvM0n8hv7Nq5BEs4LKIjevpVpbGLAJgOaYzg9wABEoX1j0JO1q2/jVkO6CVlq0dbsxZCngS5aXbysYueqA==", "dependencies": { "@formatjs/ecma402-abstract": "1.18.2", "tslib": "^2.4.0" @@ -965,23 +1408,26 @@ }, "node_modules/@formatjs/intl-getcanonicallocales": { "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@formatjs/intl-getcanonicallocales/-/intl-getcanonicallocales-1.9.2.tgz", + "integrity": "sha512-69WTStIJI2ikErOU1Il4NQKLVV8f2x6awr7+/dZz0uihuI7uQRcZtI6k/BBt4EtYaEl6w65YjUF93VuE015C0w==", "dev": true, - "license": "MIT", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@formatjs/intl-localematcher": { "version": "0.5.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.4.tgz", + "integrity": "sha512-zTwEpWOzZ2CiKcB93BLngUX59hQkuZjT2+SAQEscSm52peDW/getsawMcWF1rGRpMCX6D7nSJA3CzJ8gn13N/g==", "dependencies": { "tslib": "^2.4.0" } }, "node_modules/@humanwhocodes/config-array": { "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@humanwhocodes/object-schema": "^1.2.0", "debug": "^4.1.1", @@ -993,8 +1439,9 @@ }, "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1002,8 +1449,9 @@ }, "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -1013,13 +1461,15 @@ }, "node_modules/@humanwhocodes/object-schema": { "version": "1.2.1", - "dev": true, - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true }, "node_modules/@isaacs/cliui": { "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, - "license": "ISC", "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -1034,8 +1484,9 @@ }, "node_modules/@isaacs/cliui/node_modules/ansi-regex": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -1045,8 +1496,9 @@ }, "node_modules/@isaacs/cliui/node_modules/strip-ansi": { "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -1059,8 +1511,9 @@ }, "node_modules/@jest/types": { "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", @@ -1074,7 +1527,8 @@ }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", "dependencies": { "@jridgewell/set-array": "^1.0.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -1086,25 +1540,29 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { "version": "1.1.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.22", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", + "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -1112,8 +1570,9 @@ }, "node_modules/@mdx-js/mdx": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.0.0.tgz", + "integrity": "sha512-Icm0TBKBLYqroYbNW3BPnzMGn+7mwpQOK310aZ7+fkCtiU3aqv2cdcX+nd0Ydo3wI5Rx8bX2Z2QmGb/XcAClCw==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", "@types/estree-jsx": "^1.0.0", @@ -1146,16 +1605,18 @@ }, "node_modules/@mdx-js/mdx/node_modules/source-map": { "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">= 8" } }, "node_modules/@mdx-js/rollup": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@mdx-js/rollup/-/rollup-3.0.0.tgz", + "integrity": "sha512-ITvGiwPGEBW+D7CCnpSA9brzAosIWHAi4y+Air8wgfLnez8aWue50avHtWMfnFLCp7vt+JQ9UM8nwfuQuuydxw==", "dev": true, - "license": "MIT", "dependencies": { "@mdx-js/mdx": "^3.0.0", "@rollup/pluginutils": "^5.0.0", @@ -1172,8 +1633,9 @@ }, "node_modules/@mdx-js/rollup/node_modules/source-map": { "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">= 8" } @@ -1293,7 +1755,8 @@ }, "node_modules/@mui/lab/node_modules/clsx": { "version": "2.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", "engines": { "node": ">=6" } @@ -1344,7 +1807,8 @@ }, "node_modules/@mui/material/node_modules/clsx": { "version": "2.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", "engines": { "node": ">=6" } @@ -1447,14 +1911,16 @@ }, "node_modules/@mui/system/node_modules/clsx": { "version": "2.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", "engines": { "node": ">=6" } }, "node_modules/@mui/types": { "version": "7.2.13", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.13.tgz", + "integrity": "sha512-qP9OgacN62s+l8rdDhSFRe05HWtLLJ5TGclC9I1+tQngbssu0m2dmFZs+Px53AcOs9fD7TbYd4gc9AXzVqO/+g==", "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0" }, @@ -1551,8 +2017,9 @@ }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, - "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -1563,16 +2030,18 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, - "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, - "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -1583,8 +2052,9 @@ }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, - "license": "MIT", "optional": true, "engines": { "node": ">=14" @@ -1599,48 +2069,24 @@ "url": "https://opencollective.com/popperjs" } }, - "node_modules/@react-dnd/asap": { - "version": "4.0.1", - "license": "MIT" - }, - "node_modules/@react-dnd/invariant": { - "version": "2.0.0", - "license": "MIT" - }, - "node_modules/@react-dnd/shallowequal": { - "version": "2.0.0", - "license": "MIT" - }, - "node_modules/@rollup/plugin-inject": { - "version": "5.0.5", + "node_modules/@redux-devtools/extension": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@redux-devtools/extension/-/extension-3.3.0.tgz", + "integrity": "sha512-X34S/rC8S/M1BIrkYD1mJ5f8vlH0BDqxXrs96cvxSBo4FhMdbhU+GUGsmNYov1xjSyLMHgo8NYrUG8bNX7525g==", "dev": true, - "license": "MIT", "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "estree-walker": "^2.0.2", - "magic-string": "^0.30.3" - }, - "engines": { - "node": ">=14.0.0" + "@babel/runtime": "^7.23.2", + "immutable": "^4.3.4" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } + "redux": "^3.1.0 || ^4.0.0 || ^5.0.0" } }, - "node_modules/@rollup/plugin-inject/node_modules/estree-walker": { - "version": "2.0.2", - "dev": true, - "license": "MIT" - }, "node_modules/@rollup/pluginutils": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", + "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", @@ -1660,172 +2106,179 @@ }, "node_modules/@rollup/pluginutils/node_modules/estree-walker": { "version": "2.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.9.6", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true }, "node_modules/@sentry-internal/feedback": { - "version": "7.98.0", - "license": "MIT", + "version": "7.99.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-7.99.0.tgz", + "integrity": "sha512-exIO1o+bE0MW4z30FxC0cYzJ4ZHSMlDPMHCBDPzU+MWGQc/fb8s58QUrx5Dnm6HTh9G3H+YlroCxIo9u0GSwGQ==", "dependencies": { - "@sentry/core": "7.98.0", - "@sentry/types": "7.98.0", - "@sentry/utils": "7.98.0" + "@sentry/core": "7.99.0", + "@sentry/types": "7.99.0", + "@sentry/utils": "7.99.0" }, "engines": { "node": ">=12" } }, "node_modules/@sentry-internal/feedback/node_modules/@sentry/types": { - "version": "7.98.0", - "license": "MIT", + "version": "7.99.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.99.0.tgz", + "integrity": "sha512-94qwOw4w40sAs5mCmzcGyj8ZUu/KhnWnuMZARRq96k+SjRW/tHFAOlIdnFSrt3BLPvSOK7R3bVAskZQ0N4FTmA==", "engines": { "node": ">=8" } }, "node_modules/@sentry-internal/replay-canvas": { - "version": "7.98.0", - "license": "MIT", + "version": "7.99.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-7.99.0.tgz", + "integrity": "sha512-PoIkfusToDq0snfl2M6HJx/1KJYtXxYhQplrn11kYadO04SdG0XGXf4h7wBTMEQ7LDEAtQyvsOu4nEQtTO3YjQ==", "dependencies": { - "@sentry/core": "7.98.0", - "@sentry/replay": "7.98.0", - "@sentry/types": "7.98.0", - "@sentry/utils": "7.98.0" + "@sentry/core": "7.99.0", + "@sentry/replay": "7.99.0", + "@sentry/types": "7.99.0", + "@sentry/utils": "7.99.0" }, "engines": { "node": ">=12" } }, "node_modules/@sentry-internal/replay-canvas/node_modules/@sentry/types": { - "version": "7.98.0", - "license": "MIT", + "version": "7.99.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.99.0.tgz", + "integrity": "sha512-94qwOw4w40sAs5mCmzcGyj8ZUu/KhnWnuMZARRq96k+SjRW/tHFAOlIdnFSrt3BLPvSOK7R3bVAskZQ0N4FTmA==", "engines": { "node": ">=8" } }, "node_modules/@sentry-internal/tracing": { - "version": "7.98.0", - "license": "MIT", + "version": "7.99.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.99.0.tgz", + "integrity": "sha512-z3JQhHjoM1KdM20qrHwRClKJrNLr2CcKtCluq7xevLtXHJWNAQQbafnWD+Aoj85EWXBzKt9yJMv2ltcXJ+at+w==", "dependencies": { - "@sentry/core": "7.98.0", - "@sentry/types": "7.98.0", - "@sentry/utils": "7.98.0" + "@sentry/core": "7.99.0", + "@sentry/types": "7.99.0", + "@sentry/utils": "7.99.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry-internal/tracing/node_modules/@sentry/types": { - "version": "7.98.0", - "license": "MIT", + "version": "7.99.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.99.0.tgz", + "integrity": "sha512-94qwOw4w40sAs5mCmzcGyj8ZUu/KhnWnuMZARRq96k+SjRW/tHFAOlIdnFSrt3BLPvSOK7R3bVAskZQ0N4FTmA==", "engines": { "node": ">=8" } }, "node_modules/@sentry/browser": { - "version": "7.98.0", - "license": "MIT", + "version": "7.99.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.99.0.tgz", + "integrity": "sha512-bgfoUv3wkwwLgN5YUOe0ibB3y268ZCnamZh6nLFqnY/UBKC1+FXWFdvzVON/XKUm62LF8wlpCybOf08ebNj2yg==", "dependencies": { - "@sentry-internal/feedback": "7.98.0", - "@sentry-internal/replay-canvas": "7.98.0", - "@sentry-internal/tracing": "7.98.0", - "@sentry/core": "7.98.0", - "@sentry/replay": "7.98.0", - "@sentry/types": "7.98.0", - "@sentry/utils": "7.98.0" + "@sentry-internal/feedback": "7.99.0", + "@sentry-internal/replay-canvas": "7.99.0", + "@sentry-internal/tracing": "7.99.0", + "@sentry/core": "7.99.0", + "@sentry/replay": "7.99.0", + "@sentry/types": "7.99.0", + "@sentry/utils": "7.99.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/browser/node_modules/@sentry/types": { - "version": "7.98.0", - "license": "MIT", + "version": "7.99.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.99.0.tgz", + "integrity": "sha512-94qwOw4w40sAs5mCmzcGyj8ZUu/KhnWnuMZARRq96k+SjRW/tHFAOlIdnFSrt3BLPvSOK7R3bVAskZQ0N4FTmA==", "engines": { "node": ">=8" } }, "node_modules/@sentry/core": { - "version": "7.98.0", - "license": "MIT", + "version": "7.99.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.99.0.tgz", + "integrity": "sha512-vOAtzcAXEUtS/oW7wi3wMkZ3hsb5Ch96gKyrrj/mXdOp2zrcwdNV6N9/pawq2E9P/7Pw8AXw4CeDZztZrjQLuA==", "dependencies": { - "@sentry/types": "7.98.0", - "@sentry/utils": "7.98.0" + "@sentry/types": "7.99.0", + "@sentry/utils": "7.99.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/core/node_modules/@sentry/types": { - "version": "7.98.0", - "license": "MIT", + "version": "7.99.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.99.0.tgz", + "integrity": "sha512-94qwOw4w40sAs5mCmzcGyj8ZUu/KhnWnuMZARRq96k+SjRW/tHFAOlIdnFSrt3BLPvSOK7R3bVAskZQ0N4FTmA==", "engines": { "node": ">=8" } }, "node_modules/@sentry/replay": { - "version": "7.98.0", - "license": "MIT", + "version": "7.99.0", + "resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.99.0.tgz", + "integrity": "sha512-gyN/I2WpQrLAZDT+rScB/0jnFL2knEVBo8U8/OVt8gNP20Pq8T/rDZKO/TG0cBfvULDUbJj2P4CJryn2p/O2rA==", "dependencies": { - "@sentry-internal/tracing": "7.98.0", - "@sentry/core": "7.98.0", - "@sentry/types": "7.98.0", - "@sentry/utils": "7.98.0" + "@sentry-internal/tracing": "7.99.0", + "@sentry/core": "7.99.0", + "@sentry/types": "7.99.0", + "@sentry/utils": "7.99.0" }, "engines": { "node": ">=12" } }, "node_modules/@sentry/replay/node_modules/@sentry/types": { - "version": "7.98.0", - "license": "MIT", + "version": "7.99.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.99.0.tgz", + "integrity": "sha512-94qwOw4w40sAs5mCmzcGyj8ZUu/KhnWnuMZARRq96k+SjRW/tHFAOlIdnFSrt3BLPvSOK7R3bVAskZQ0N4FTmA==", "engines": { "node": ">=8" } }, "node_modules/@sentry/types": { "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.19.7.tgz", + "integrity": "sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg==", "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">=6" } }, "node_modules/@sentry/utils": { - "version": "7.98.0", - "license": "MIT", + "version": "7.99.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.99.0.tgz", + "integrity": "sha512-cYZy5WNTkWs5GgggGnjfGqC44CWir0pAv4GVVSx0fsup4D4pMKBJPrtub15f9uC+QkUf3vVkqwpBqeFxtmJQTQ==", "dependencies": { - "@sentry/types": "7.98.0" + "@sentry/types": "7.99.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/utils/node_modules/@sentry/types": { - "version": "7.98.0", - "license": "MIT", + "version": "7.99.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.99.0.tgz", + "integrity": "sha512-94qwOw4w40sAs5mCmzcGyj8ZUu/KhnWnuMZARRq96k+SjRW/tHFAOlIdnFSrt3BLPvSOK7R3bVAskZQ0N4FTmA==", "engines": { "node": ">=8" } }, "node_modules/@stomp/stompjs": { "version": "6.1.2", - "license": "Apache-2.0" + "resolved": "https://registry.npmjs.org/@stomp/stompjs/-/stompjs-6.1.2.tgz", + "integrity": "sha512-FHDTrIFM5Ospi4L3Xhj6v2+NzCVAeNDcBe95YjUWhWiRMrBF6uN3I7AUOlRgT6jU/2WQvvYK8ZaIxFfxFp+uHQ==" }, "node_modules/@svgr/babel-plugin-add-jsx-attribute": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", "dev": true, - "license": "MIT", "engines": { "node": ">=14" }, @@ -1839,8 +2292,9 @@ }, "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", "dev": true, - "license": "MIT", "engines": { "node": ">=14" }, @@ -1854,8 +2308,9 @@ }, "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", "dev": true, - "license": "MIT", "engines": { "node": ">=14" }, @@ -1869,8 +2324,9 @@ }, "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", + "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=14" }, @@ -1884,8 +2340,9 @@ }, "node_modules/@svgr/babel-plugin-svg-dynamic-title": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", + "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", "dev": true, - "license": "MIT", "engines": { "node": ">=14" }, @@ -1899,8 +2356,9 @@ }, "node_modules/@svgr/babel-plugin-svg-em-dimensions": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", + "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", "dev": true, - "license": "MIT", "engines": { "node": ">=14" }, @@ -1914,8 +2372,9 @@ }, "node_modules/@svgr/babel-plugin-transform-react-native-svg": { "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", + "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=14" }, @@ -1929,8 +2388,9 @@ }, "node_modules/@svgr/babel-plugin-transform-svg-component": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", + "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -1944,8 +2404,9 @@ }, "node_modules/@svgr/babel-preset": { "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", + "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", "dev": true, - "license": "MIT", "dependencies": { "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", @@ -1969,8 +2430,9 @@ }, "node_modules/@svgr/core": { "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", + "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/core": "^7.21.3", "@svgr/babel-preset": "8.1.0", @@ -1988,8 +2450,9 @@ }, "node_modules/@svgr/core/node_modules/camelcase": { "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -1999,8 +2462,9 @@ }, "node_modules/@svgr/hast-util-to-babel-ast": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", + "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.21.3", "entities": "^4.4.0" @@ -2015,8 +2479,9 @@ }, "node_modules/@svgr/plugin-jsx": { "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", + "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/core": "^7.21.3", "@svgr/babel-preset": "8.1.0", @@ -2036,8 +2501,9 @@ }, "node_modules/@testing-library/dom": { "version": "9.3.4", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz", + "integrity": "sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", @@ -2055,8 +2521,9 @@ }, "node_modules/@testing-library/jest-dom": { "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz", + "integrity": "sha512-ynmNeT7asXyH3aSVv4vvX4Rb+0qjOhdNHnO/3vuZNqPmhDpV/+rCSGwQ7bLcmU2cJ4dvoheIO85LQj0IbJHEtg==", "dev": true, - "license": "MIT", "dependencies": { "@adobe/css-tools": "^4.0.1", "@babel/runtime": "^7.9.2", @@ -2076,8 +2543,9 @@ }, "node_modules/@testing-library/jest-dom/node_modules/chalk": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2088,8 +2556,9 @@ }, "node_modules/@testing-library/react": { "version": "12.1.5", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-12.1.5.tgz", + "integrity": "sha512-OfTXCJUFgjd/digLUuPxa0+/3ZxsQmE7ub9kcbW/wi96Bh3o/p5vrETcBGfP17NWPGqeYYl5LTRpwyGoMC4ysg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.5", "@testing-library/dom": "^8.0.0", @@ -2105,8 +2574,9 @@ }, "node_modules/@testing-library/react/node_modules/@testing-library/dom": { "version": "8.20.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.1.tgz", + "integrity": "sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g==", "dev": true, - "license": "MIT", "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -2123,8 +2593,9 @@ }, "node_modules/@testing-library/user-event": { "version": "13.5.0", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.5.0.tgz", + "integrity": "sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.5" }, @@ -2138,8 +2609,9 @@ }, "node_modules/@tginternal/language-util": { "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@tginternal/language-util/-/language-util-1.0.6.tgz", + "integrity": "sha512-PHe6+0zbeFCCAfOJsfGfk1mWReQB2GvO5vEl674dAI0Wi05e+ufJN8HeMzGu2onEFqp+yQrHbJp9JjExEQie6g==", "dev": true, - "license": "MIT", "dependencies": { "@formatjs/intl-getcanonicallocales": "^1.7.0", "latinize": "^0.5.0" @@ -2147,8 +2619,9 @@ }, "node_modules/@tolgee/cli": { "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@tolgee/cli/-/cli-1.3.2.tgz", + "integrity": "sha512-7Vf+BFGmQ9jLfDiRrhsgg+h494k0V8BacSdKVZV83PqhibI6/+H9boJvB1oSA+IEwAO9BoBFxy87Y1LN0NI1Cg==", "dev": true, - "license": "MIT", "dependencies": { "ansi-colors": "^4.1.3", "base32-decode": "^1.0.0", @@ -2171,46 +2644,53 @@ } }, "node_modules/@tolgee/core": { - "version": "5.19.3", - "license": "MIT" + "version": "5.19.5", + "resolved": "https://registry.npmjs.org/@tolgee/core/-/core-5.19.5.tgz", + "integrity": "sha512-utj50vn5J12dwgqAKGQOeT0mFD3tTuFQukuXvLbvY3E5VpiXFX8Cvj83W6gUecvp9bn5F38LPeNbBtZ8zIf3iQ==" }, "node_modules/@tolgee/format-icu": { - "version": "5.19.3", - "license": "MIT" + "version": "5.19.5", + "resolved": "https://registry.npmjs.org/@tolgee/format-icu/-/format-icu-5.19.5.tgz", + "integrity": "sha512-lX7Yor06za8JmmSc3sH7EAQEnMOlN22NyqkfGsu6hBipbdm0RY181rvKTuMKL++Jgy6NxjtqfB5T7eYjPyihLg==" }, "node_modules/@tolgee/react": { - "version": "5.19.3", - "license": "MIT", + "version": "5.19.5", + "resolved": "https://registry.npmjs.org/@tolgee/react/-/react-5.19.5.tgz", + "integrity": "sha512-IJYmXEPWX27GVUq1qSd3wM36RduWNXDERq95KFMYLV8B6VE01oASxXxtQ0DwPECXGcjmeCPrvs+0GjeOzff4Bw==", "dependencies": { - "@tolgee/web": "5.19.3" + "@tolgee/web": "5.19.5" }, "peerDependencies": { "react": "^16.14.0 || ^17.0.1 || ^18.1.0" } }, "node_modules/@tolgee/web": { - "version": "5.19.3", - "license": "BSD-3-Clause", + "version": "5.19.5", + "resolved": "https://registry.npmjs.org/@tolgee/web/-/web-5.19.5.tgz", + "integrity": "sha512-9CQ2FSVKwtaenlXHwACt7Tp502lpZtD086jG4gXsOb+xzD3WSkVuw+IyPN1+dlQntoA0NvkM7ALJ7vkzZu7BIw==", "dependencies": { - "@tolgee/core": "5.19.3" + "@tolgee/core": "5.19.5" } }, "node_modules/@types/acorn": { "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", + "integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "*" } }, "node_modules/@types/aria-query": { "version": "5.0.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true }, "node_modules/@types/babel__core": { "version": "7.20.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", @@ -2221,14 +2701,16 @@ }, "node_modules/@types/babel__generator": { "version": "7.6.8", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", "dependencies": { "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__template": { "version": "7.4.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" @@ -2236,104 +2718,122 @@ }, "node_modules/@types/babel__traverse": { "version": "7.20.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", + "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", "dependencies": { "@babel/types": "^7.20.7" } }, "node_modules/@types/codemirror": { "version": "5.60.15", + "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.15.tgz", + "integrity": "sha512-dTOvwEQ+ouKJ/rE9LT1Ue2hmP6H1mZv5+CCnNWu2qtiOe2LQa9lCprEY20HxiDmV/Bxh+dXjywmy5aKvoGjULA==", "dev": true, - "license": "MIT", "dependencies": { "@types/tern": "*" } }, "node_modules/@types/d3-array": { "version": "3.2.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==" }, "node_modules/@types/d3-color": { "version": "3.1.3", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" }, "node_modules/@types/d3-ease": { "version": "3.0.2", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==" }, "node_modules/@types/d3-interpolate": { "version": "3.0.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", "dependencies": { "@types/d3-color": "*" } }, "node_modules/@types/d3-path": { "version": "3.0.2", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.2.tgz", + "integrity": "sha512-WAIEVlOCdd/NKRYTsqCpOMHQHemKBEINf8YXMYOtXH0GA7SY0dqMB78P3Uhgfy+4X+/Mlw2wDtlETkN6kQUCMA==" }, "node_modules/@types/d3-scale": { "version": "4.0.8", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", + "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", "dependencies": { "@types/d3-time": "*" } }, "node_modules/@types/d3-shape": { "version": "3.1.6", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.6.tgz", + "integrity": "sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==", "dependencies": { "@types/d3-path": "*" } }, "node_modules/@types/d3-time": { "version": "3.0.3", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz", + "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==" }, "node_modules/@types/d3-timer": { "version": "3.0.2", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==" }, "node_modules/@types/debug": { "version": "4.1.12", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", "dependencies": { "@types/ms": "*" } }, "node_modules/@types/diff": { "version": "5.0.9", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/diff/-/diff-5.0.9.tgz", + "integrity": "sha512-RWVEhh/zGXpAVF/ZChwNnv7r4rvqzJ7lYNSmZSVTxjV0PBLf6Qu7RNg+SUtkpzxmiNkjCx0Xn2tPp7FIkshJwQ==", + "dev": true }, "node_modules/@types/estree": { "version": "1.0.5", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" }, "node_modules/@types/estree-jsx": { - "version": "1.0.3", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.4.tgz", + "integrity": "sha512-5idy3hvI9lAMqsyilBM+N+boaCf1MgoefbDxN6KEO5aK17TOHwFAYT9sjxzeKAiIWRUBgLxmZ9mPcnzZXtTcRQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "*" } }, "node_modules/@types/hast": { - "version": "3.0.3", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/unist": "*" } }, "node_modules/@types/history": { "version": "4.7.11", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", + "dev": true }, "node_modules/@types/hoist-non-react-statics": { "version": "3.3.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", + "integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==", "dependencies": { "@types/react": "*", "hoist-non-react-statics": "^3.3.0" @@ -2341,29 +2841,33 @@ }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "dev": true, - "license": "MIT", "dependencies": { "@types/istanbul-lib-coverage": "*" } }, "node_modules/@types/istanbul-reports": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/istanbul-lib-report": "*" } }, "node_modules/@types/jest": { "version": "26.0.24", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.24.tgz", + "integrity": "sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w==", "dev": true, - "license": "MIT", "dependencies": { "jest-diff": "^26.0.0", "pretty-format": "^26.0.0" @@ -2371,8 +2875,9 @@ }, "node_modules/@types/jest/node_modules/pretty-format": { "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^26.6.2", "ansi-regex": "^5.0.0", @@ -2385,72 +2890,86 @@ }, "node_modules/@types/jest/node_modules/react-is": { "version": "17.0.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true }, "node_modules/@types/json-schema": { "version": "7.0.15", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" }, "node_modules/@types/json5": { "version": "0.0.29", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true }, "node_modules/@types/lodash": { "version": "4.14.202", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", + "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==" }, "node_modules/@types/mdast": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz", + "integrity": "sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==", "dev": true, - "license": "MIT", "dependencies": { "@types/unist": "*" } }, "node_modules/@types/mdx": { - "version": "2.0.10", - "dev": true, - "license": "MIT" + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.11.tgz", + "integrity": "sha512-HM5bwOaIQJIQbAYfax35HCKxx7a3KrK3nBtIqJgSOitivTD1y3oW9P3rxY9RkXYPUk7y/AjAohfHKmFpGE79zw==", + "dev": true }, "node_modules/@types/minimist": { "version": "1.2.5", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", + "dev": true }, "node_modules/@types/ms": { "version": "0.7.34", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" }, "node_modules/@types/node": { - "version": "18.19.10", + "version": "18.19.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.14.tgz", + "integrity": "sha512-EnQ4Us2rmOS64nHDWr0XqAD8DsO6f3XR6lf9UIIrZQpUzPVdN/oPuEzfDWNHSyXLvoGgjuEm/sPwFGSSs35Wtg==", "devOptional": true, - "license": "MIT", "dependencies": { "undici-types": "~5.26.4" } }, "node_modules/@types/normalize-package-data": { "version": "2.4.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true }, "node_modules/@types/parse-json": { "version": "4.0.2", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" }, "node_modules/@types/prismjs": { "version": "1.26.3", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.3.tgz", + "integrity": "sha512-A0D0aTXvjlqJ5ZILMz3rNfDBOx9hHxLZYv2by47Sm/pqW35zzjusrZTryatjN/Rf8Us2gZrJD+KeHbUSTux1Cw==" }, "node_modules/@types/prop-types": { "version": "15.7.11", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" }, "node_modules/@types/react": { "version": "17.0.75", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.75.tgz", + "integrity": "sha512-MSA+NzEzXnQKrqpO63CYqNstFjsESgvJAdAyyJ1n6ZQq/GLgf6nOfIKwk+Twuz0L1N6xPe+qz5xRCJrbhMaLsw==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -2459,23 +2978,26 @@ }, "node_modules/@types/react-dom": { "version": "17.0.25", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.25.tgz", + "integrity": "sha512-urx7A7UxkZQmThYA4So0NelOVjx3V4rNFVJwp0WZlbIK5eM4rNJDiN3R/E9ix0MBh6kAEojk/9YL+Te6D9zHNA==", "dev": true, - "license": "MIT", "dependencies": { "@types/react": "^17" } }, "node_modules/@types/react-list": { "version": "0.8.11", + "resolved": "https://registry.npmjs.org/@types/react-list/-/react-list-0.8.11.tgz", + "integrity": "sha512-mUfWOutmUDUicT9T1MySV6jLtbFnslyZCvXhIWGnAIah6GZsSF4yUXnX8UfdLP/PptCRPVpjxO/ksneU7j1y+A==", "dev": true, - "license": "MIT", "dependencies": { "@types/react": "*" } }, "node_modules/@types/react-redux": { "version": "7.1.33", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.33.tgz", + "integrity": "sha512-NF8m5AjWCkert+fosDsN3hAlHzpjSiXlVy9EgQEmLoBhaNXbmyeGs/aj5dQzKuF+/q+S7JQagorGDW8pJ28Hmg==", "dependencies": { "@types/hoist-non-react-statics": "^3.3.0", "@types/react": "*", @@ -2485,8 +3007,9 @@ }, "node_modules/@types/react-router": { "version": "5.1.20", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", + "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", "dev": true, - "license": "MIT", "dependencies": { "@types/history": "^4.7.11", "@types/react": "*" @@ -2494,8 +3017,9 @@ }, "node_modules/@types/react-router-dom": { "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", "dev": true, - "license": "MIT", "dependencies": { "@types/history": "^4.7.11", "@types/react": "*", @@ -2504,74 +3028,85 @@ }, "node_modules/@types/react-transition-group": { "version": "4.4.10", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", + "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", "dependencies": { "@types/react": "*" } }, "node_modules/@types/scheduler": { "version": "0.16.8", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", + "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==" }, "node_modules/@types/semver": { "version": "7.5.6", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", + "dev": true }, "node_modules/@types/tern": { "version": "0.23.9", + "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.9.tgz", + "integrity": "sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "*" } }, "node_modules/@types/testing-library__jest-dom": { "version": "5.14.9", + "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.9.tgz", + "integrity": "sha512-FSYhIjFlfOpGSRyVoMBMuS3ws5ehFQODymf3vlI7U1K8c7PHwWwFY7VREfmsuzHSOnoKs/9/Y983ayOs7eRzqw==", "dev": true, - "license": "MIT", "dependencies": { "@types/jest": "*" } }, "node_modules/@types/unist": { "version": "3.0.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==", + "dev": true }, "node_modules/@types/yargs": { "version": "15.0.19", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.19.tgz", + "integrity": "sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==", "dev": true, - "license": "MIT", "dependencies": { "@types/yargs-parser": "*" } }, "node_modules/@types/yargs-parser": { "version": "21.0.3", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true }, "node_modules/@types/yup": { "version": "0.29.14", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/yup/-/yup-0.29.14.tgz", + "integrity": "sha512-Ynb/CjHhE/Xp/4bhHmQC4U1Ox+I2OpfRYF3dnNgQqn1cHa6LK3H1wJMNPT02tSVZA6FYuXE2ITORfbnb6zBCSA==", + "dev": true }, "node_modules/@types/zxcvbn": { "version": "4.4.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/zxcvbn/-/zxcvbn-4.4.4.tgz", + "integrity": "sha512-Tuk4q7q0DnpzyJDI4aMeghGuFu2iS1QAdKpabn8JfbtfGmVDUgvZv1I7mEjP61Bvnp3ljKCC8BE6YYSTNxmvRQ==", + "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.19.1", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.19.1", - "@typescript-eslint/type-utils": "6.19.1", - "@typescript-eslint/utils": "6.19.1", - "@typescript-eslint/visitor-keys": "6.19.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -2597,14 +3132,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.19.1", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "6.19.1", - "@typescript-eslint/types": "6.19.1", - "@typescript-eslint/typescript-estree": "6.19.1", - "@typescript-eslint/visitor-keys": "6.19.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4" }, "engines": { @@ -2624,12 +3160,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.19.1", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "6.19.1", - "@typescript-eslint/visitor-keys": "6.19.1" + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2640,12 +3177,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.19.1", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "6.19.1", - "@typescript-eslint/utils": "6.19.1", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -2666,9 +3204,10 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.19.1", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", "dev": true, - "license": "MIT", "engines": { "node": "^16.0.0 || >=18.0.0" }, @@ -2678,12 +3217,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.19.1", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "6.19.1", - "@typescript-eslint/visitor-keys": "6.19.1", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2705,16 +3245,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.19.1", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.19.1", - "@typescript-eslint/types": "6.19.1", - "@typescript-eslint/typescript-estree": "6.19.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", "semver": "^7.5.4" }, "engines": { @@ -2729,11 +3270,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.19.1", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/types": "6.21.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -2746,12 +3288,14 @@ }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true }, "node_modules/@vitejs/plugin-react": { "version": "4.2.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.1.tgz", + "integrity": "sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==", "dependencies": { "@babel/core": "^7.23.5", "@babel/plugin-transform-react-jsx-self": "^7.23.3", @@ -2768,8 +3312,9 @@ }, "node_modules/acorn": { "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true, - "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -2779,16 +3324,18 @@ }, "node_modules/acorn-jsx": { "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, - "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "node_modules/ajv": { "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, - "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -2802,24 +3349,27 @@ }, "node_modules/ansi-colors": { "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/ansi-regex": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -2832,8 +3382,9 @@ }, "node_modules/anymatch": { "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, - "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -2844,24 +3395,30 @@ }, "node_modules/argparse": { "version": "2.0.1", - "dev": true, - "license": "Python-2.0" + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "node_modules/aria-query": { "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", "dev": true, - "license": "Apache-2.0", "dependencies": { "deep-equal": "^2.0.5" } }, "node_modules/array-buffer-byte-length": { - "version": "1.0.0", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2869,8 +3426,9 @@ }, "node_modules/array-includes": { "version": "3.1.7", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", + "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -2887,16 +3445,18 @@ }, "node_modules/array-union": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/array.prototype.flat": { "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -2912,8 +3472,9 @@ }, "node_modules/array.prototype.flatmap": { "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -2928,28 +3489,31 @@ } }, "node_modules/array.prototype.tosorted": { - "version": "1.1.2", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz", + "integrity": "sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.2.1" + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.1.0", + "es-shim-unscopables": "^1.0.2" } }, "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.2", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", "dev": true, - "license": "MIT", "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-array-buffer": "^3.0.2", + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", "is-shared-array-buffer": "^1.0.2" }, "engines": { @@ -2961,73 +3525,51 @@ }, "node_modules/arrify": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/asn1.js": { - "version": "5.4.1", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.0", - "dev": true, - "license": "MIT" - }, - "node_modules/assert": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "is-nan": "^1.3.2", - "object-is": "^1.1.5", - "object.assign": "^4.1.4", - "util": "^0.12.5" - } - }, "node_modules/astral-regex": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/astring": { "version": "1.8.6", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.8.6.tgz", + "integrity": "sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==", "dev": true, - "license": "MIT", "bin": { "astring": "bin/astring" } }, "node_modules/asynciterator.prototype": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz", + "integrity": "sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==", "dev": true, - "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" } }, "node_modules/asynckit": { "version": "0.4.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true }, "node_modules/available-typed-arrays": { - "version": "1.0.5", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.6.tgz", + "integrity": "sha512-j1QzY8iPNPG4o4xmO3ptzpRxTciqD3MgEHtifP/YnJpIo58Xu+ne4BejlbkuaLfXn/nz6HFiw29bLpj2PNMdGg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -3037,7 +3579,8 @@ }, "node_modules/babel-plugin-macros": { "version": "3.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", "dependencies": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", @@ -3050,7 +3593,8 @@ }, "node_modules/babel-plugin-macros/node_modules/cosmiconfig": { "version": "7.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", "dependencies": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", @@ -3064,7 +3608,8 @@ }, "node_modules/bail": { "version": "2.0.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -3072,64 +3617,46 @@ }, "node_modules/balanced-match": { "version": "1.0.2", - "license": "MIT" + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/base32-decode": { "version": "1.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" + "resolved": "https://registry.npmjs.org/base32-decode/-/base32-decode-1.0.0.tgz", + "integrity": "sha512-KNWUX/R7wKenwE/G/qFMzGScOgVntOmbE27vvc6GrniDGYb6a5+qWcuoXl8WIOQL7q0TpK7nZDm1Y04Yi3Yn5g==", + "dev": true }, "node_modules/big-integer": { "version": "1.6.52", - "license": "Unlicense", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", "engines": { "node": ">=0.6" } }, "node_modules/binary-extensions": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/bn.js": { - "version": "5.2.1", - "dev": true, - "license": "MIT" - }, "node_modules/brace-expansion": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/braces": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, - "license": "MIT", "dependencies": { "fill-range": "^7.0.1" }, @@ -3139,7 +3666,8 @@ }, "node_modules/broadcast-channel": { "version": "3.7.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/broadcast-channel/-/broadcast-channel-3.7.0.tgz", + "integrity": "sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==", "dependencies": { "@babel/runtime": "^7.7.2", "detect-node": "^2.1.0", @@ -3151,91 +3679,10 @@ "unload": "2.2.0" } }, - "node_modules/brorand": { - "version": "1.1.0", - "dev": true, - "license": "MIT" - }, - "node_modules/browser-resolve": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve": "^1.17.0" - } - }, - "node_modules/browserify-aes": { - "version": "1.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/browserify-cipher": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "node_modules/browserify-des": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/browserify-rsa": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^5.0.0", - "randombytes": "^2.0.1" - } - }, - "node_modules/browserify-sign": { - "version": "4.2.2", - "dev": true, - "license": "ISC", - "dependencies": { - "bn.js": "^5.2.1", - "browserify-rsa": "^4.1.0", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.4", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.6", - "readable-stream": "^3.6.2", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/browserify-zlib": { - "version": "0.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "pako": "~1.0.5" - } - }, "node_modules/browserslist": { "version": "4.22.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.3.tgz", + "integrity": "sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==", "funding": [ { "type": "opencollective", @@ -3250,7 +3697,6 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { "caniuse-lite": "^1.0.30001580", "electron-to-chromium": "^1.4.648", @@ -3264,51 +3710,20 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/buffer": { - "version": "5.7.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, "node_modules/buffer-crc32": { "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true, - "license": "MIT", "engines": { "node": "*" } }, - "node_modules/buffer-xor": { - "version": "1.0.3", - "dev": true, - "license": "MIT" - }, - "node_modules/builtin-status-codes": { - "version": "3.0.0", - "dev": true, - "license": "MIT" - }, "node_modules/call-bind": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", "dev": true, - "license": "MIT", "dependencies": { "function-bind": "^1.1.2", "get-intrinsic": "^1.2.1", @@ -3320,23 +3735,26 @@ }, "node_modules/callsites": { "version": "3.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "engines": { "node": ">=6" } }, "node_modules/camelcase": { "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/camelcase-keys": { "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", "dev": true, - "license": "MIT", "dependencies": { "camelcase": "^5.3.1", "map-obj": "^4.0.0", @@ -3350,7 +3768,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001581", + "version": "1.0.30001584", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001584.tgz", + "integrity": "sha512-LOz7CCQ9M1G7OjJOF9/mzmqmj3jE/7VOmrfw6Mgs0E8cjOsbRXQJHsPBfmBOXDskXKrHLyyW3n7kpDW/4BsfpQ==", "funding": [ { "type": "opencollective", @@ -3364,13 +3784,13 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ], - "license": "CC-BY-4.0" + ] }, "node_modules/ccount": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", "dev": true, - "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -3378,8 +3798,9 @@ }, "node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -3393,7 +3814,8 @@ }, "node_modules/character-entities": { "version": "2.0.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -3401,8 +3823,9 @@ }, "node_modules/character-entities-html4": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", "dev": true, - "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -3410,8 +3833,9 @@ }, "node_modules/character-entities-legacy": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", "dev": true, - "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -3419,8 +3843,9 @@ }, "node_modules/character-reference-invalid": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", "dev": true, - "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -3428,6 +3853,8 @@ }, "node_modules/chokidar": { "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, "funding": [ { @@ -3435,7 +3862,6 @@ "url": "https://paulmillr.com/funding/" } ], - "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -3452,30 +3878,24 @@ "fsevents": "~2.3.2" } }, - "node_modules/cipher-base": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, "node_modules/clsx": { "version": "1.2.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", "engines": { "node": ">=6" } }, "node_modules/codemirror": { "version": "5.65.16", - "license": "MIT" + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.16.tgz", + "integrity": "sha512-br21LjYmSlVL0vFCPWPfhzUCT34FM/pAdK7rRIZwa0rrtrIdotvP4Oh4GUHsu2E3IrQMCfRkL/fN3ytMNxVQvg==" }, "node_modules/collapse-white-space": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", + "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", "dev": true, - "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -3483,8 +3903,9 @@ }, "node_modules/color-convert": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -3494,13 +3915,15 @@ }, "node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/combined-stream": { "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, - "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -3510,7 +3933,8 @@ }, "node_modules/comma-separated-tokens": { "version": "2.0.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -3518,40 +3942,36 @@ }, "node_modules/commander": { "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=16" } }, "node_modules/concat-map": { "version": "0.0.1", - "license": "MIT" - }, - "node_modules/console-browserify": { - "version": "1.2.0", - "dev": true - }, - "node_modules/constants-browserify": { - "version": "1.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/convert-source-map": { "version": "1.9.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, "node_modules/copy-to-clipboard": { "version": "3.3.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", + "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", "dependencies": { "toggle-selection": "^1.0.6" } }, "node_modules/cosmiconfig": { "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", "dev": true, - "license": "MIT", "dependencies": { "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", @@ -3573,58 +3993,16 @@ } } }, - "node_modules/create-ecdh": { - "version": "4.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - } - }, - "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.12.0", - "dev": true, - "license": "MIT" - }, - "node_modules/create-hash": { - "version": "1.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "node_modules/create-hmac": { - "version": "1.1.7", - "dev": true, - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "node_modules/create-require": { - "version": "1.1.1", - "dev": true, - "license": "MIT" - }, "node_modules/cropperjs": { "version": "1.6.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/cropperjs/-/cropperjs-1.6.1.tgz", + "integrity": "sha512-F4wsi+XkDHCOMrHMYjrTEE4QBOrsHHN5/2VsVAaRq8P7E5z7xQpT75S+f/9WikmBEailas3+yo+6zPIomW+NOA==" }, "node_modules/cross-spawn": { "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, - "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -3634,39 +4012,21 @@ "node": ">= 8" } }, - "node_modules/crypto-browserify": { - "version": "3.12.0", - "dev": true, - "license": "MIT", - "dependencies": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - }, - "engines": { - "node": "*" - } - }, "node_modules/css.escape": { "version": "1.5.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true }, "node_modules/csstype": { "version": "3.1.3", - "license": "MIT" + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/d3-array": { "version": "3.2.4", - "license": "ISC", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", "dependencies": { "internmap": "1 - 2" }, @@ -3676,28 +4036,32 @@ }, "node_modules/d3-color": { "version": "3.1.0", - "license": "ISC", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", "engines": { "node": ">=12" } }, "node_modules/d3-ease": { "version": "3.0.1", - "license": "BSD-3-Clause", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", "engines": { "node": ">=12" } }, "node_modules/d3-format": { "version": "3.1.0", - "license": "ISC", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", "engines": { "node": ">=12" } }, "node_modules/d3-interpolate": { "version": "3.0.1", - "license": "ISC", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", "dependencies": { "d3-color": "1 - 3" }, @@ -3707,14 +4071,16 @@ }, "node_modules/d3-path": { "version": "3.1.0", - "license": "ISC", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", "engines": { "node": ">=12" } }, "node_modules/d3-scale": { "version": "4.0.2", - "license": "ISC", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", @@ -3728,7 +4094,8 @@ }, "node_modules/d3-shape": { "version": "3.2.0", - "license": "ISC", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", "dependencies": { "d3-path": "^3.1.0" }, @@ -3738,7 +4105,8 @@ }, "node_modules/d3-time": { "version": "3.1.0", - "license": "ISC", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", "dependencies": { "d3-array": "2 - 3" }, @@ -3748,7 +4116,8 @@ }, "node_modules/d3-time-format": { "version": "4.1.0", - "license": "ISC", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", "dependencies": { "d3-time": "1 - 3" }, @@ -3758,14 +4127,16 @@ }, "node_modules/d3-timer": { "version": "3.0.1", - "license": "ISC", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", "engines": { "node": ">=12" } }, "node_modules/date-fns": { "version": "2.29.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.2.tgz", + "integrity": "sha512-0VNbwmWJDS/G3ySwFSJA3ayhbURMTJLtwM2DTxf9CWondCnh6DTNlO9JgRSq6ibf4eD0lfMJNBxUdEAHHix+bA==", "engines": { "node": ">=0.11" }, @@ -3776,7 +4147,8 @@ }, "node_modules/debug": { "version": "4.3.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { "ms": "2.1.2" }, @@ -3791,16 +4163,18 @@ }, "node_modules/decamelize": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/decamelize-keys": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", "dev": true, - "license": "MIT", "dependencies": { "decamelize": "^1.1.0", "map-obj": "^1.0.0" @@ -3814,19 +4188,22 @@ }, "node_modules/decamelize-keys/node_modules/map-obj": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/decimal.js-light": { "version": "2.5.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==" }, "node_modules/decode-named-character-reference": { "version": "1.0.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", "dependencies": { "character-entities": "^2.0.0" }, @@ -3837,8 +4214,9 @@ }, "node_modules/deep-equal": { "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", "dev": true, - "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.0", "call-bind": "^1.0.5", @@ -3868,41 +4246,23 @@ }, "node_modules/deep-is": { "version": "0.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/deep-rename-keys": { - "version": "0.2.1", - "license": "MIT", - "dependencies": { - "kind-of": "^3.0.2", - "rename-keys": "^1.1.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/deep-rename-keys/node_modules/kind-of": { - "version": "3.2.2", - "license": "MIT", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true }, "node_modules/deepmerge": { "version": "2.2.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz", + "integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==", "engines": { "node": ">=0.10.0" } }, "node_modules/define-data-property": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", "dev": true, - "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.1", "gopd": "^1.0.1", @@ -3914,8 +4274,9 @@ }, "node_modules/define-properties": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, - "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", @@ -3930,36 +4291,31 @@ }, "node_modules/delayed-stream": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.4.0" } }, "node_modules/dequal": { "version": "2.0.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "engines": { "node": ">=6" } }, - "node_modules/des.js": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, "node_modules/detect-node": { "version": "2.1.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" }, "node_modules/devlop": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", "dev": true, - "license": "MIT", "dependencies": { "dequal": "^2.0.0" }, @@ -3970,38 +4326,26 @@ }, "node_modules/diff": { "version": "5.1.0", - "license": "BSD-3-Clause", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", "engines": { "node": ">=0.3.1" } }, "node_modules/diff-sequences": { "version": "26.6.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", + "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", "dev": true, - "license": "MIT", "engines": { "node": ">= 10.14.2" } }, - "node_modules/diffie-hellman": { - "version": "5.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.12.0", - "dev": true, - "license": "MIT" - }, "node_modules/dir-glob": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, - "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, @@ -4009,19 +4353,11 @@ "node": ">=8" } }, - "node_modules/dnd-core": { - "version": "14.0.1", - "license": "MIT", - "dependencies": { - "@react-dnd/asap": "^4.0.0", - "@react-dnd/invariant": "^2.0.0", - "redux": "^4.1.1" - } - }, "node_modules/doctrine": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, - "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -4031,32 +4367,24 @@ }, "node_modules/dom-accessibility-api": { "version": "0.5.16", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true }, "node_modules/dom-helpers": { "version": "5.2.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", "dependencies": { "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" } }, - "node_modules/domain-browser": { - "version": "4.23.0", - "dev": true, - "license": "Artistic-2.0", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://bevry.me/fund" - } - }, "node_modules/dot-case": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", "dev": true, - "license": "MIT", "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" @@ -4064,7 +4392,8 @@ }, "node_modules/dotenv": { "version": "16.4.1", - "license": "BSD-2-Clause", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.1.tgz", + "integrity": "sha512-CjA3y+Dr3FyFDOAMnxZEGtnW9KBR2M0JvvUtXNW+dYJL5ROWxP9DUHCwgFqpMk0OXCc0ljhaNTr2w/kutYIcHQ==", "engines": { "node": ">=12" }, @@ -4074,7 +4403,8 @@ }, "node_modules/dotenv-flow": { "version": "4.0.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/dotenv-flow/-/dotenv-flow-4.0.1.tgz", + "integrity": "sha512-HuCQ487bSA43mtlxdWpyk5jt5Lljy+v1I8y/2l96gtjSve9p3OvJZCCOhQnz2hY4VhLogFfXpY20zBygMwaydA==", "dependencies": { "dotenv": "^16.0.0" }, @@ -4084,41 +4414,26 @@ }, "node_modules/eastasianwidth": { "version": "0.2.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.648", - "license": "ISC" - }, - "node_modules/elliptic": { - "version": "6.5.4", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.0", - "dev": true, - "license": "MIT" + "version": "1.4.656", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.656.tgz", + "integrity": "sha512-9AQB5eFTHyR3Gvt2t/NwR0le2jBSUNwCnMbUCejFWHD+so4tH40/dRLgoE+jxlPeWS43XJewyvCv+I8LPMl49Q==" }, "node_modules/emoji-regex": { "version": "9.2.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true }, "node_modules/enquirer": { "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-colors": "^4.1.1", "strip-ansi": "^6.0.1" @@ -4129,8 +4444,9 @@ }, "node_modules/entities": { "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true, - "license": "BSD-2-Clause", "engines": { "node": ">=0.12" }, @@ -4140,15 +4456,17 @@ }, "node_modules/error-ex": { "version": "1.3.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dependencies": { "is-arrayish": "^0.2.1" } }, "node_modules/es-abstract": { "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", "dev": true, - "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.0", "arraybuffer.prototype.slice": "^1.0.2", @@ -4197,10 +4515,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-get-iterator": { "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.3", @@ -4218,8 +4546,9 @@ }, "node_modules/es-iterator-helpers": { "version": "1.0.15", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz", + "integrity": "sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==", "dev": true, - "license": "MIT", "dependencies": { "asynciterator.prototype": "^1.0.0", "call-bind": "^1.0.2", @@ -4239,8 +4568,9 @@ }, "node_modules/es-set-tostringtag": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", + "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", "dev": true, - "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.2", "has-tostringtag": "^1.0.0", @@ -4252,16 +4582,18 @@ }, "node_modules/es-shim-unscopables": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", "dev": true, - "license": "MIT", "dependencies": { "hasown": "^2.0.0" } }, "node_modules/es-to-primitive": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, - "license": "MIT", "dependencies": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -4276,8 +4608,9 @@ }, "node_modules/esbuild": { "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", "hasInstallScript": true, - "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -4311,15 +4644,17 @@ } }, "node_modules/escalade": { - "version": "3.1.1", - "license": "MIT", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "engines": { "node": ">=6" } }, "node_modules/escape-string-regexp": { "version": "4.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "engines": { "node": ">=10" }, @@ -4329,8 +4664,9 @@ }, "node_modules/eslint": { "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/code-frame": "7.12.11", "@eslint/eslintrc": "^0.4.3", @@ -4385,8 +4721,9 @@ }, "node_modules/eslint-plugin-prettier": { "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz", + "integrity": "sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==", "dev": true, - "license": "MIT", "dependencies": { "prettier-linter-helpers": "^1.0.0" }, @@ -4405,8 +4742,9 @@ }, "node_modules/eslint-plugin-react": { "version": "7.33.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz", + "integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==", "dev": true, - "license": "MIT", "dependencies": { "array-includes": "^3.1.6", "array.prototype.flatmap": "^1.3.1", @@ -4434,8 +4772,9 @@ }, "node_modules/eslint-plugin-react/node_modules/brace-expansion": { "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -4443,8 +4782,9 @@ }, "node_modules/eslint-plugin-react/node_modules/doctrine": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, - "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -4454,8 +4794,9 @@ }, "node_modules/eslint-plugin-react/node_modules/minimatch": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -4465,8 +4806,9 @@ }, "node_modules/eslint-plugin-react/node_modules/resolve": { "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", "dev": true, - "license": "MIT", "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -4481,16 +4823,18 @@ }, "node_modules/eslint-plugin-react/node_modules/semver": { "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/eslint-scope": { "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -4501,16 +4845,18 @@ }, "node_modules/eslint-scope/node_modules/estraverse": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, - "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/eslint-utils": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", "dev": true, - "license": "MIT", "dependencies": { "eslint-visitor-keys": "^1.1.0" }, @@ -4523,16 +4869,18 @@ }, "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=4" } }, "node_modules/eslint-visitor-keys": { "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -4542,24 +4890,27 @@ }, "node_modules/eslint/node_modules/@babel/code-frame": { "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/highlight": "^7.10.4" } }, "node_modules/eslint/node_modules/argparse": { "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, - "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" } }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -4567,16 +4918,18 @@ }, "node_modules/eslint/node_modules/eslint-visitor-keys": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=10" } }, "node_modules/eslint/node_modules/globals": { "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, - "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -4589,16 +4942,18 @@ }, "node_modules/eslint/node_modules/ignore": { "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/eslint/node_modules/js-yaml": { "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, - "license": "MIT", "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -4609,8 +4964,9 @@ }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -4620,8 +4976,9 @@ }, "node_modules/eslint/node_modules/type-fest": { "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, - "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -4631,8 +4988,9 @@ }, "node_modules/espree": { "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "acorn": "^7.4.0", "acorn-jsx": "^5.3.1", @@ -4644,16 +5002,18 @@ }, "node_modules/espree/node_modules/eslint-visitor-keys": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=4" } }, "node_modules/esprima": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, - "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -4664,8 +5024,9 @@ }, "node_modules/esquery": { "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -4675,8 +5036,9 @@ }, "node_modules/esrecurse": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -4686,16 +5048,18 @@ }, "node_modules/estraverse": { "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/estree-util-attach-comments": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", + "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "^1.0.0" }, @@ -4706,8 +5070,9 @@ }, "node_modules/estree-util-build-jsx": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", + "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", "devlop": "^1.0.0", @@ -4721,8 +5086,9 @@ }, "node_modules/estree-util-is-identifier-name": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", "dev": true, - "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" @@ -4730,8 +5096,9 @@ }, "node_modules/estree-util-to-js": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", + "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", "astring": "^1.8.0", @@ -4744,16 +5111,18 @@ }, "node_modules/estree-util-to-js/node_modules/source-map": { "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">= 8" } }, "node_modules/estree-util-visit": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", + "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/unist": "^3.0.0" @@ -4765,72 +5134,65 @@ }, "node_modules/estree-walker": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "^1.0.0" } }, "node_modules/esutils": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, - "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/eventemitter3": { "version": "4.0.7", - "license": "MIT" - }, - "node_modules/events": { - "version": "3.3.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, "node_modules/eventsource": { "version": "2.0.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", + "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", "engines": { "node": ">=12.0.0" } }, - "node_modules/evp_bytestokey": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, "node_modules/extend": { "version": "3.0.2", - "license": "MIT" + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "node_modules/fast-deep-equal": { "version": "3.1.3", - "license": "MIT" + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true }, "node_modules/fast-diff": { "version": "1.3.0", - "dev": true, - "license": "Apache-2.0" + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true }, "node_modules/fast-equals": { "version": "5.0.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.0.1.tgz", + "integrity": "sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==", "engines": { "node": ">=6.0.0" } }, "node_modules/fast-glob": { "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, - "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -4844,25 +5206,29 @@ }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true }, "node_modules/fast-levenshtein": { "version": "2.0.6", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true }, "node_modules/fastq": { - "version": "1.17.0", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, - "license": "ISC", "dependencies": { "reusify": "^1.0.4" } }, "node_modules/faye-websocket": { "version": "0.11.4", - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "dependencies": { "websocket-driver": ">=0.5.1" }, @@ -4872,20 +5238,23 @@ }, "node_modules/fd-slicer": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", "dev": true, - "license": "MIT", "dependencies": { "pend": "~1.2.0" } }, "node_modules/fflate": { "version": "0.4.8", - "license": "MIT" + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", + "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==" }, "node_modules/file-entry-cache": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, - "license": "MIT", "dependencies": { "flat-cache": "^3.0.4" }, @@ -4895,8 +5264,9 @@ }, "node_modules/fill-range": { "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, - "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -4906,12 +5276,14 @@ }, "node_modules/find-root": { "version": "1.1.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" }, "node_modules/find-up": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, - "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -4922,8 +5294,9 @@ }, "node_modules/flat-cache": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, - "license": "MIT", "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", @@ -4935,21 +5308,24 @@ }, "node_modules/flatted": { "version": "3.2.9", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true }, "node_modules/for-each": { "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", "dev": true, - "license": "MIT", "dependencies": { "is-callable": "^1.1.3" } }, "node_modules/foreground-child": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", "dev": true, - "license": "ISC", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -4963,8 +5339,9 @@ }, "node_modules/form-data": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dev": true, - "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -4976,13 +5353,14 @@ }, "node_modules/formik": { "version": "2.4.5", + "resolved": "https://registry.npmjs.org/formik/-/formik-2.4.5.tgz", + "integrity": "sha512-Gxlht0TD3vVdzMDHwkiNZqJ7Mvg77xQNfmBRrNtvzcHZs72TJppSTDKHpImCMJZwcWPBJ8jSQQ95GJzXFf1nAQ==", "funding": [ { "type": "individual", "url": "https://opencollective.com/formik" } ], - "license": "Apache-2.0", "dependencies": { "@types/hoist-non-react-statics": "^3.3.1", "deepmerge": "^2.1.1", @@ -4999,8 +5377,9 @@ }, "node_modules/fs-extra": { "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", "dev": true, - "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -5012,19 +5391,35 @@ }, "node_modules/fs.realpath": { "version": "1.0.0", - "license": "ISC" + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } }, "node_modules/function-bind": { "version": "1.1.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/function.prototype.name": { "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -5040,42 +5435,51 @@ }, "node_modules/functional-red-black-tree": { "version": "1.0.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true }, "node_modules/functions-have-names": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/gensync": { "version": "1.0.0-beta.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "engines": { "node": ">=6.9.0" } }, "node_modules/get-intrinsic": { - "version": "1.2.2", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.3.tgz", + "integrity": "sha512-JIcZczvcMVE7AUOP+X72bh8HqHBRxFdz5PDHYtNG/lE3yk9b3KZBJlwFcTyPYjg3L4RLLmZJzvjxhaZVapxFrQ==", "dev": true, - "license": "MIT", "dependencies": { + "es-errors": "^1.0.0", "function-bind": "^1.1.2", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", "hasown": "^2.0.0" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/get-symbol-description": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" @@ -5089,8 +5493,9 @@ }, "node_modules/glob": { "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", "dev": true, - "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^2.3.5", @@ -5110,8 +5515,9 @@ }, "node_modules/glob-parent": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -5121,15 +5527,17 @@ }, "node_modules/globals": { "version": "11.12.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "engines": { "node": ">=4" } }, "node_modules/globalthis": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", "dev": true, - "license": "MIT", "dependencies": { "define-properties": "^1.1.3" }, @@ -5142,13 +5550,15 @@ }, "node_modules/globalyzer": { "version": "0.1.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", + "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", + "dev": true }, "node_modules/globby": { "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, - "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -5166,13 +5576,15 @@ }, "node_modules/globrex": { "version": "0.1.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true }, "node_modules/gopd": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "dev": true, - "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -5182,42 +5594,48 @@ }, "node_modules/graceful-fs": { "version": "4.2.11", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true }, "node_modules/graphemer": { "version": "1.4.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true }, "node_modules/hard-rejection": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/has-bigints": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-flag": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/has-property-descriptors": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", "dev": true, - "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.2" }, @@ -5227,8 +5645,9 @@ }, "node_modules/has-proto": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -5238,8 +5657,9 @@ }, "node_modules/has-symbols": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -5248,11 +5668,12 @@ } }, "node_modules/has-tostringtag": { - "version": "1.0.0", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, - "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" + "has-symbols": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -5261,31 +5682,10 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hash-base": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hash.js": { - "version": "1.1.7", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, "node_modules/hasown": { "version": "2.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", "dependencies": { "function-bind": "^1.1.2" }, @@ -5295,8 +5695,9 @@ }, "node_modules/hast-util-is-element": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", "dev": true, - "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" }, @@ -5307,8 +5708,9 @@ }, "node_modules/hast-util-to-estree": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.0.tgz", + "integrity": "sha512-lfX5g6hqVh9kjS/B9E2gSkvHH4SZNiQFiqWS0x9fENzEl+8W12RqdRxX6d/Cwxi30tPQs3bIO+aolQJNp1bIyw==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", "@types/estree-jsx": "^1.0.0", @@ -5334,8 +5736,9 @@ }, "node_modules/hast-util-to-jsx-runtime": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.0.tgz", + "integrity": "sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", "@types/hast": "^3.0.0", @@ -5360,21 +5763,24 @@ }, "node_modules/hast-util-to-jsx-runtime/node_modules/inline-style-parser": { "version": "0.2.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.2.tgz", + "integrity": "sha512-EcKzdTHVe8wFVOGEYXiW9WmJXPjqi1T+234YpJr98RiFYKHV3cdy1+3mkTE+KHTHxFFLH51SfaGOoUdW+v7ViQ==", + "dev": true }, "node_modules/hast-util-to-jsx-runtime/node_modules/style-to-object": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.5.tgz", + "integrity": "sha512-rDRwHtoDD3UMMrmZ6BzOW0naTjMsVZLIjsGleSKS/0Oz+cgCfAPRspaqJuE8rDzpKha/nEvnM0IF4seEAZUTKQ==", "dev": true, - "license": "MIT", "dependencies": { "inline-style-parser": "0.2.2" } }, "node_modules/hast-util-to-text": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.0.tgz", + "integrity": "sha512-EWiE1FSArNBPUo1cKWtzqgnuRQwEeQbQtnFJRYV1hb1BWDgrAlBU0ExptvZMM/KSA82cDpm2sFGf3Dmc5Mza3w==", "dev": true, - "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", @@ -5388,8 +5794,9 @@ }, "node_modules/hast-util-whitespace": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", "dev": true, - "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" }, @@ -5400,15 +5807,17 @@ }, "node_modules/highlight.js": { "version": "11.9.0", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.9.0.tgz", + "integrity": "sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==", "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">=12.0.0" } }, "node_modules/history": { "version": "4.10.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", "dependencies": { "@babel/runtime": "^7.1.2", "loose-envify": "^1.2.0", @@ -5418,31 +5827,24 @@ "value-equal": "^1.0.1" } }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", - "license": "BSD-3-Clause", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", "dependencies": { "react-is": "^16.7.0" } }, "node_modules/hoist-non-react-statics/node_modules/react-is": { "version": "16.13.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/hosted-git-info": { "version": "3.0.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz", + "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", "dev": true, - "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -5452,8 +5854,9 @@ }, "node_modules/hosted-git-info/node_modules/lru-cache": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, - "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -5463,48 +5866,34 @@ }, "node_modules/hosted-git-info/node_modules/yallist": { "version": "4.0.0", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/http-parser-js": { "version": "0.5.8", - "license": "MIT" - }, - "node_modules/https-browserify": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/ieee754": { - "version": "1.2.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" }, "node_modules/ignore": { - "version": "5.3.0", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "dev": true, - "license": "MIT", "engines": { "node": ">= 4" } }, + "node_modules/immutable": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", + "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", + "dev": true + }, "node_modules/import-fresh": { "version": "3.3.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -5518,23 +5907,26 @@ }, "node_modules/imurmurhash": { "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.8.19" } }, "node_modules/indent-string": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/inflight": { "version": "1.0.6", - "license": "ISC", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -5542,20 +5934,19 @@ }, "node_modules/inherits": { "version": "2.0.4", - "license": "ISC" - }, - "node_modules/initials": { - "version": "3.1.2", - "license": "MIT" + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/inline-style-parser": { "version": "0.1.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" }, "node_modules/internal-slot": { "version": "1.0.6", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", + "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", "dev": true, - "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.2", "hasown": "^2.0.0", @@ -5567,14 +5958,16 @@ }, "node_modules/internmap": { "version": "2.0.3", - "license": "ISC", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", "engines": { "node": ">=12" } }, "node_modules/intl-messageformat": { "version": "9.13.0", - "license": "BSD-3-Clause", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-9.13.0.tgz", + "integrity": "sha512-7sGC7QnSQGa5LZP7bXLDhVDtQOeKGeBFGHF2Y8LVBwYZoQZCgWeKoPGTa5GMG8g/TzDgeXuYJQis7Ggiw2xTOw==", "dependencies": { "@formatjs/ecma402-abstract": "1.11.4", "@formatjs/fast-memoize": "1.2.1", @@ -5584,7 +5977,8 @@ }, "node_modules/intl-messageformat/node_modules/@formatjs/ecma402-abstract": { "version": "1.11.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.4.tgz", + "integrity": "sha512-EBikYFp2JCdIfGEb5G9dyCkTGDmC57KSHhRQOC3aYxoPWVZvfWCDjZwkGYHN7Lis/fmuWl906bnNTJifDQ3sXw==", "dependencies": { "@formatjs/intl-localematcher": "0.2.25", "tslib": "^2.1.0" @@ -5592,7 +5986,8 @@ }, "node_modules/intl-messageformat/node_modules/@formatjs/icu-messageformat-parser": { "version": "2.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.1.0.tgz", + "integrity": "sha512-Qxv/lmCN6hKpBSss2uQ8IROVnta2r9jd3ymUEIjm2UyIkUCHVcbUVRGL/KS/wv7876edvsPe+hjHVJ4z8YuVaw==", "dependencies": { "@formatjs/ecma402-abstract": "1.11.4", "@formatjs/icu-skeleton-parser": "1.3.6", @@ -5601,7 +5996,8 @@ }, "node_modules/intl-messageformat/node_modules/@formatjs/icu-skeleton-parser": { "version": "1.3.6", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.6.tgz", + "integrity": "sha512-I96mOxvml/YLrwU2Txnd4klA7V8fRhb6JG/4hm3VMNmeJo1F03IpV2L3wWt7EweqNLES59SZ4d6hVOPCSf80Bg==", "dependencies": { "@formatjs/ecma402-abstract": "1.11.4", "tslib": "^2.1.0" @@ -5609,15 +6005,17 @@ }, "node_modules/intl-messageformat/node_modules/@formatjs/intl-localematcher": { "version": "0.2.25", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.25.tgz", + "integrity": "sha512-YmLcX70BxoSopLFdLr1Ds99NdlTI2oWoLbaUW2M406lxOIPzE1KQhRz2fPUkq34xVZQaihCoU29h0KK7An3bhA==", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/is-alphabetical": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", "dev": true, - "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -5625,8 +6023,9 @@ }, "node_modules/is-alphanumerical": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", "dev": true, - "license": "MIT", "dependencies": { "is-alphabetical": "^2.0.0", "is-decimal": "^2.0.0" @@ -5638,8 +6037,9 @@ }, "node_modules/is-arguments": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -5652,13 +6052,16 @@ } }, "node_modules/is-array-buffer": { - "version": "3.0.2", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5666,12 +6069,14 @@ }, "node_modules/is-arrayish": { "version": "0.2.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, "node_modules/is-async-function": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", "dev": true, - "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -5684,8 +6089,9 @@ }, "node_modules/is-bigint": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "dev": true, - "license": "MIT", "dependencies": { "has-bigints": "^1.0.1" }, @@ -5695,8 +6101,9 @@ }, "node_modules/is-binary-path": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, - "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -5706,8 +6113,9 @@ }, "node_modules/is-boolean-object": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -5719,14 +6127,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-buffer": { - "version": "1.1.6", - "license": "MIT" - }, "node_modules/is-callable": { "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -5736,7 +6141,8 @@ }, "node_modules/is-core-module": { "version": "2.13.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dependencies": { "hasown": "^2.0.0" }, @@ -5746,8 +6152,9 @@ }, "node_modules/is-date-object": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "dev": true, - "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -5760,8 +6167,9 @@ }, "node_modules/is-decimal": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", "dev": true, - "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -5769,16 +6177,18 @@ }, "node_modules/is-extglob": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/is-finalizationregistry": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2" }, @@ -5788,16 +6198,18 @@ }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/is-generator-function": { "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", "dev": true, - "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -5810,8 +6222,9 @@ }, "node_modules/is-glob": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, - "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -5821,8 +6234,9 @@ }, "node_modules/is-hexadecimal": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", "dev": true, - "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -5830,31 +6244,18 @@ }, "node_modules/is-map": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-nan": { - "version": "1.3.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-negative-zero": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -5864,16 +6265,18 @@ }, "node_modules/is-number": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.12.0" } }, "node_modules/is-number-object": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, - "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -5886,24 +6289,27 @@ }, "node_modules/is-plain-obj": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/is-reference": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", + "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "*" } }, "node_modules/is-regex": { "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -5917,16 +6323,18 @@ }, "node_modules/is-set": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-shared-array-buffer": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2" }, @@ -5936,8 +6344,9 @@ }, "node_modules/is-string": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "dev": true, - "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -5950,8 +6359,9 @@ }, "node_modules/is-symbol": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dev": true, - "license": "MIT", "dependencies": { "has-symbols": "^1.0.2" }, @@ -5963,11 +6373,12 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.12", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", "dev": true, - "license": "MIT", "dependencies": { - "which-typed-array": "^1.1.11" + "which-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" @@ -5978,16 +6389,18 @@ }, "node_modules/is-weakmap": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-weakref": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2" }, @@ -5997,8 +6410,9 @@ }, "node_modules/is-weakset": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" @@ -6009,26 +6423,21 @@ }, "node_modules/isarray": { "version": "2.0.5", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true }, "node_modules/isexe": { "version": "2.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/isomorphic-timers-promises": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true }, "node_modules/iterator.prototype": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", "dev": true, - "license": "MIT", "dependencies": { "define-properties": "^1.2.1", "get-intrinsic": "^1.2.1", @@ -6039,8 +6448,9 @@ }, "node_modules/jackspeak": { "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", "dev": true, - "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -6056,8 +6466,9 @@ }, "node_modules/jest-diff": { "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", + "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", "dev": true, - "license": "MIT", "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^26.6.2", @@ -6070,8 +6481,9 @@ }, "node_modules/jest-diff/node_modules/pretty-format": { "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^26.6.2", "ansi-regex": "^5.0.0", @@ -6084,29 +6496,34 @@ }, "node_modules/jest-diff/node_modules/react-is": { "version": "17.0.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true }, "node_modules/jest-get-type": { "version": "26.3.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", + "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", "dev": true, - "license": "MIT", "engines": { "node": ">= 10.14.2" } }, "node_modules/js-sha3": { "version": "0.8.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" }, "node_modules/js-tokens": { "version": "4.0.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/js-yaml": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, - "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -6116,7 +6533,8 @@ }, "node_modules/jsesc": { "version": "2.5.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "bin": { "jsesc": "bin/jsesc" }, @@ -6126,26 +6544,31 @@ }, "node_modules/json-buffer": { "version": "3.0.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "node_modules/json-schema-traverse": { "version": "0.4.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true }, "node_modules/json5": { "version": "2.2.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "bin": { "json5": "lib/cli.js" }, @@ -6155,8 +6578,9 @@ }, "node_modules/jsonfile": { "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, - "license": "MIT", "dependencies": { "universalify": "^2.0.0" }, @@ -6166,8 +6590,9 @@ }, "node_modules/jsx-ast-utils": { "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", "dev": true, - "license": "MIT", "dependencies": { "array-includes": "^3.1.6", "array.prototype.flat": "^1.3.1", @@ -6180,36 +6605,41 @@ }, "node_modules/keyv": { "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, - "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } }, "node_modules/kind-of": { "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/kleur": { "version": "4.1.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", "engines": { "node": ">=6" } }, "node_modules/latinize": { "version": "0.5.0", - "dev": true, - "license": "BSD" + "resolved": "https://registry.npmjs.org/latinize/-/latinize-0.5.0.tgz", + "integrity": "sha512-SHzxgdcFP/64lUEfX3183QALY2KdSQxad3gmhCc/b03QN1mbx0AnJWvsQjqoJLbucY9pJuK+NMbnasUIocDmnQ==", + "dev": true }, "node_modules/levn": { "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, - "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -6220,12 +6650,14 @@ }, "node_modules/lines-and-columns": { "version": "1.2.4", - "license": "MIT" + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "node_modules/locate-path": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, - "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -6235,26 +6667,31 @@ }, "node_modules/lodash": { "version": "4.17.21", - "license": "MIT" + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash-es": { "version": "4.17.21", - "license": "MIT" + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" }, "node_modules/lodash.merge": { "version": "4.6.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true }, "node_modules/lodash.truncate": { "version": "4.4.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true }, "node_modules/longest-streak": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", "dev": true, - "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -6262,7 +6699,8 @@ }, "node_modules/loose-envify": { "version": "1.4.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -6272,16 +6710,18 @@ }, "node_modules/lower-case": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", "dev": true, - "license": "MIT", "dependencies": { "tslib": "^2.0.3" } }, "node_modules/lowlight": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-3.1.0.tgz", + "integrity": "sha512-CEbNVoSikAxwDMDPjXlqlFYiZLkDJHwyGu/MfOsJnF3d7f3tds5J3z8s/l9TMXhzfsJCCJEAsD78842mwmg0PQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "devlop": "^1.0.0", @@ -6294,34 +6734,26 @@ }, "node_modules/lru-cache": { "version": "5.1.1", - "license": "ISC", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dependencies": { "yallist": "^3.0.2" } }, "node_modules/lz-string": { "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, - "license": "MIT", "bin": { "lz-string": "bin/bin.js" } }, - "node_modules/magic-string": { - "version": "0.30.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/map-obj": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" }, @@ -6331,8 +6763,9 @@ }, "node_modules/markdown-extensions": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", + "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=16" }, @@ -6342,25 +6775,17 @@ }, "node_modules/match-sorter": { "version": "6.3.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/match-sorter/-/match-sorter-6.3.3.tgz", + "integrity": "sha512-sgiXxrRijEe0SzHKGX4HouCpfHRPnqteH42UdMEW7BlWy990ZkzcvonJGv4Uu9WE7Y1f8Yocm91+4qFPCbmNww==", "dependencies": { "@babel/runtime": "^7.23.8", "remove-accents": "0.5.0" } }, - "node_modules/md5.js": { - "version": "1.3.5", - "dev": true, - "license": "MIT", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, "node_modules/mdast-util-definitions": { "version": "5.1.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz", + "integrity": "sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==", "dependencies": { "@types/mdast": "^3.0.0", "@types/unist": "^2.0.0", @@ -6373,18 +6798,21 @@ }, "node_modules/mdast-util-definitions/node_modules/@types/mdast": { "version": "3.0.15", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz", + "integrity": "sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==", "dependencies": { "@types/unist": "^2" } }, "node_modules/mdast-util-definitions/node_modules/@types/unist": { "version": "2.0.10", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", + "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==" }, "node_modules/mdast-util-definitions/node_modules/unist-util-is": { "version": "5.2.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", "dependencies": { "@types/unist": "^2.0.0" }, @@ -6395,7 +6823,8 @@ }, "node_modules/mdast-util-definitions/node_modules/unist-util-visit": { "version": "4.1.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", + "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==", "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0", @@ -6408,7 +6837,8 @@ }, "node_modules/mdast-util-definitions/node_modules/unist-util-visit-parents": { "version": "5.1.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", + "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0" @@ -6420,8 +6850,9 @@ }, "node_modules/mdast-util-from-markdown": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.0.tgz", + "integrity": "sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA==", "dev": true, - "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", @@ -6443,8 +6874,9 @@ }, "node_modules/mdast-util-mdx": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", "dev": true, - "license": "MIT", "dependencies": { "mdast-util-from-markdown": "^2.0.0", "mdast-util-mdx-expression": "^2.0.0", @@ -6459,8 +6891,9 @@ }, "node_modules/mdast-util-mdx-expression": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz", + "integrity": "sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", @@ -6476,8 +6909,9 @@ }, "node_modules/mdast-util-mdx-jsx": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.0.0.tgz", + "integrity": "sha512-XZuPPzQNBPAlaqsTTgRrcJnyFbSOBovSadFgbFu8SnuNgm+6Bdx1K+IWoitsmj6Lq6MNtI+ytOqwN70n//NaBA==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", @@ -6500,8 +6934,9 @@ }, "node_modules/mdast-util-mdxjs-esm": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", @@ -6516,9 +6951,10 @@ } }, "node_modules/mdast-util-phrasing": { - "version": "4.0.0", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", "dev": true, - "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "unist-util-is": "^6.0.0" @@ -6530,8 +6966,9 @@ }, "node_modules/mdast-util-to-hast": { "version": "13.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.1.0.tgz", + "integrity": "sha512-/e2l/6+OdGp/FB+ctrJ9Avz71AN/GRH3oi/3KAx/kMnoUsD6q0woXlDT8lLEeViVKE7oZxE7RXzvO3T8kF2/sA==", "dev": true, - "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", @@ -6550,8 +6987,9 @@ }, "node_modules/mdast-util-to-markdown": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz", + "integrity": "sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", @@ -6569,8 +7007,9 @@ }, "node_modules/mdast-util-to-string": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", "dev": true, - "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0" }, @@ -6581,8 +7020,9 @@ }, "node_modules/meow": { "version": "9.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", + "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/minimist": "^1.2.0", "camelcase-keys": "^6.2.2", @@ -6606,14 +7046,17 @@ }, "node_modules/merge2": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/micromark": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", + "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", "dev": true, "funding": [ { @@ -6625,7 +7068,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", @@ -6648,6 +7090,8 @@ }, "node_modules/micromark-core-commonmark": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.0.tgz", + "integrity": "sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA==", "dev": true, "funding": [ { @@ -6659,7 +7103,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", @@ -6681,6 +7124,8 @@ }, "node_modules/micromark-extension-mdx-expression": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.0.tgz", + "integrity": "sha512-sI0nwhUDz97xyzqJAbHQhp5TfaxEvZZZ2JDqUo+7NvyIYG6BZ5CPPqj2ogUoPJlmXHBnyZUzISg9+oUmU6tUjQ==", "dev": true, "funding": [ { @@ -6692,7 +7137,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", @@ -6706,8 +7150,9 @@ }, "node_modules/micromark-extension-mdx-jsx": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.0.tgz", + "integrity": "sha512-uvhhss8OGuzR4/N17L1JwvmJIpPhAd8oByMawEKx6NVdBCbesjH4t+vjEp3ZXft9DwvlKSD07fCeI44/N0Vf2w==", "dev": true, - "license": "MIT", "dependencies": { "@types/acorn": "^4.0.0", "@types/estree": "^1.0.0", @@ -6727,8 +7172,9 @@ }, "node_modules/micromark-extension-mdx-md": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", "dev": true, - "license": "MIT", "dependencies": { "micromark-util-types": "^2.0.0" }, @@ -6739,8 +7185,9 @@ }, "node_modules/micromark-extension-mdxjs": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", "dev": true, - "license": "MIT", "dependencies": { "acorn": "^8.0.0", "acorn-jsx": "^5.0.0", @@ -6758,8 +7205,9 @@ }, "node_modules/micromark-extension-mdxjs-esm": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", @@ -6778,8 +7226,9 @@ }, "node_modules/micromark-extension-mdxjs/node_modules/acorn": { "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, - "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -6789,6 +7238,8 @@ }, "node_modules/micromark-factory-destination": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", + "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", "dev": true, "funding": [ { @@ -6800,7 +7251,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", @@ -6809,6 +7259,8 @@ }, "node_modules/micromark-factory-label": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", + "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", "dev": true, "funding": [ { @@ -6820,7 +7272,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-util-character": "^2.0.0", @@ -6830,6 +7281,8 @@ }, "node_modules/micromark-factory-mdx-expression": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.1.tgz", + "integrity": "sha512-F0ccWIUHRLRrYp5TC9ZYXmZo+p2AM13ggbsW4T0b5CRKP8KHVRB8t4pwtBgTxtjRmwrK0Irwm7vs2JOZabHZfg==", "dev": true, "funding": [ { @@ -6841,7 +7294,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", @@ -6855,6 +7307,8 @@ }, "node_modules/micromark-factory-space": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", "dev": true, "funding": [ { @@ -6866,7 +7320,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-types": "^2.0.0" @@ -6874,6 +7327,8 @@ }, "node_modules/micromark-factory-title": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", + "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", "dev": true, "funding": [ { @@ -6885,7 +7340,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", @@ -6895,6 +7349,8 @@ }, "node_modules/micromark-factory-whitespace": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", + "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", "dev": true, "funding": [ { @@ -6906,7 +7362,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", @@ -6916,6 +7371,8 @@ }, "node_modules/micromark-util-character": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", "dev": true, "funding": [ { @@ -6927,7 +7384,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" @@ -6935,6 +7391,8 @@ }, "node_modules/micromark-util-chunked": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", + "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", "dev": true, "funding": [ { @@ -6946,13 +7404,14 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "node_modules/micromark-util-classify-character": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", + "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", "dev": true, "funding": [ { @@ -6964,7 +7423,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", @@ -6973,6 +7431,8 @@ }, "node_modules/micromark-util-combine-extensions": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", + "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", "dev": true, "funding": [ { @@ -6984,7 +7444,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-util-chunked": "^2.0.0", "micromark-util-types": "^2.0.0" @@ -6992,6 +7451,8 @@ }, "node_modules/micromark-util-decode-numeric-character-reference": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", + "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", "dev": true, "funding": [ { @@ -7003,13 +7464,14 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "node_modules/micromark-util-decode-string": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", + "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", "dev": true, "funding": [ { @@ -7021,7 +7483,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "decode-named-character-reference": "^1.0.0", "micromark-util-character": "^2.0.0", @@ -7031,6 +7492,8 @@ }, "node_modules/micromark-util-encode": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", + "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", "dev": true, "funding": [ { @@ -7041,11 +7504,12 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ], - "license": "MIT" + ] }, "node_modules/micromark-util-events-to-acorn": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.2.tgz", + "integrity": "sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==", "dev": true, "funding": [ { @@ -7057,7 +7521,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "@types/acorn": "^4.0.0", "@types/estree": "^1.0.0", @@ -7071,6 +7534,8 @@ }, "node_modules/micromark-util-html-tag-name": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", + "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", "dev": true, "funding": [ { @@ -7081,11 +7546,12 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ], - "license": "MIT" + ] }, "node_modules/micromark-util-normalize-identifier": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", + "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", "dev": true, "funding": [ { @@ -7097,13 +7563,14 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "node_modules/micromark-util-resolve-all": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", + "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", "dev": true, "funding": [ { @@ -7115,13 +7582,14 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-util-types": "^2.0.0" } }, "node_modules/micromark-util-sanitize-uri": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", + "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", "dev": true, "funding": [ { @@ -7133,7 +7601,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-encode": "^2.0.0", @@ -7142,6 +7609,8 @@ }, "node_modules/micromark-util-subtokenize": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.0.tgz", + "integrity": "sha512-vc93L1t+gpR3p8jxeVdaYlbV2jTYteDje19rNSS/H5dlhxUYll5Fy6vJ2cDwP8RnsXi818yGty1ayP55y3W6fg==", "dev": true, "funding": [ { @@ -7153,7 +7622,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", @@ -7163,6 +7631,8 @@ }, "node_modules/micromark-util-symbol": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", "dev": true, "funding": [ { @@ -7173,11 +7643,12 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ], - "license": "MIT" + ] }, "node_modules/micromark-util-types": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", + "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", "dev": true, "funding": [ { @@ -7188,13 +7659,13 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ], - "license": "MIT" + ] }, "node_modules/micromatch": { "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, - "license": "MIT", "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -7205,29 +7676,14 @@ }, "node_modules/microseconds": { "version": "0.2.0", - "license": "MIT" - }, - "node_modules/miller-rabin": { - "version": "4.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "bin": { - "miller-rabin": "bin/miller-rabin" - } - }, - "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.12.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/microseconds/-/microseconds-0.2.0.tgz", + "integrity": "sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==" }, "node_modules/mime": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", "dev": true, - "license": "MIT", "bin": { "mime": "cli.js" }, @@ -7237,16 +7693,18 @@ }, "node_modules/mime-db": { "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, - "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -7256,26 +7714,18 @@ }, "node_modules/min-indent": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "dev": true, - "license": "ISC" - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, "node_modules/minimatch": { "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -7288,16 +7738,18 @@ }, "node_modules/minimist": { "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/minimist-options": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", "dev": true, - "license": "MIT", "dependencies": { "arrify": "^1.0.1", "is-plain-obj": "^1.1.0", @@ -7309,43 +7761,49 @@ }, "node_modules/minipass": { "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "dev": true, - "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/mri": { "version": "1.2.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", "engines": { "node": ">=4" } }, "node_modules/ms": { "version": "2.1.2", - "license": "MIT" + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/nano-time": { "version": "1.0.0", - "license": "ISC", + "resolved": "https://registry.npmjs.org/nano-time/-/nano-time-1.0.0.tgz", + "integrity": "sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA==", "dependencies": { "big-integer": "^1.6.16" } }, "node_modules/nanoclone": { "version": "0.2.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/nanoclone/-/nanoclone-0.2.1.tgz", + "integrity": "sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==" }, "node_modules/nanoid": { "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -7355,13 +7813,15 @@ }, "node_modules/natural-compare": { "version": "1.4.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true }, "node_modules/no-case": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", "dev": true, - "license": "MIT", "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" @@ -7369,8 +7829,9 @@ }, "node_modules/node-fetch": { "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dev": true, - "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -7388,54 +7849,14 @@ }, "node_modules/node-releases": { "version": "2.0.14", - "license": "MIT" - }, - "node_modules/node-stdlib-browser": { - "version": "1.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "assert": "^2.0.0", - "browser-resolve": "^2.0.0", - "browserify-zlib": "^0.2.0", - "buffer": "^5.7.1", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "create-require": "^1.1.1", - "crypto-browserify": "^3.11.0", - "domain-browser": "^4.22.0", - "events": "^3.0.0", - "https-browserify": "^1.0.0", - "isomorphic-timers-promises": "^1.0.1", - "os-browserify": "^0.3.0", - "path-browserify": "^1.0.1", - "pkg-dir": "^5.0.0", - "process": "^0.11.10", - "punycode": "^1.4.1", - "querystring-es3": "^0.2.1", - "readable-stream": "^3.6.0", - "stream-browserify": "^3.0.0", - "stream-http": "^3.2.0", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", - "tty-browserify": "0.0.1", - "url": "^0.11.0", - "util": "^0.12.4", - "vm-browserify": "^1.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-stdlib-browser/node_modules/punycode": { - "version": "1.4.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" }, "node_modules/normalize-package-data": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "hosted-git-info": "^4.0.1", "is-core-module": "^2.5.0", @@ -7448,8 +7869,9 @@ }, "node_modules/normalize-package-data/node_modules/hosted-git-info": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", "dev": true, - "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -7459,8 +7881,9 @@ }, "node_modules/normalize-package-data/node_modules/lru-cache": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, - "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -7470,20 +7893,23 @@ }, "node_modules/normalize-package-data/node_modules/yallist": { "version": "4.0.0", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/normalize-path": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/notistack": { "version": "2.0.8", - "license": "MIT", + "resolved": "https://registry.npmjs.org/notistack/-/notistack-2.0.8.tgz", + "integrity": "sha512-/IY14wkFp5qjPgKNvAdfL5Jp6q90+MjgKTPh4c81r/lW70KeuX6b9pE/4f8L4FG31cNudbN9siiFS5ql1aSLRw==", "dependencies": { "clsx": "^1.1.0", "hoist-non-react-statics": "^3.3.0" @@ -7510,23 +7936,26 @@ }, "node_modules/object-assign": { "version": "4.1.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "engines": { "node": ">=0.10.0" } }, "node_modules/object-inspect": { "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/object-is": { "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -7540,16 +7969,18 @@ }, "node_modules/object-keys": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/object.assign": { "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.5", "define-properties": "^1.2.1", @@ -7565,8 +7996,9 @@ }, "node_modules/object.entries": { "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", + "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -7578,8 +8010,9 @@ }, "node_modules/object.fromentries": { "version": "2.0.7", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", + "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -7594,8 +8027,9 @@ }, "node_modules/object.hasown": { "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz", + "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==", "dev": true, - "license": "MIT", "dependencies": { "define-properties": "^1.2.0", "es-abstract": "^1.22.1" @@ -7606,8 +8040,9 @@ }, "node_modules/object.values": { "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", + "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -7622,19 +8057,22 @@ }, "node_modules/oblivious-set": { "version": "1.0.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/oblivious-set/-/oblivious-set-1.0.0.tgz", + "integrity": "sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==" }, "node_modules/once": { "version": "1.4.0", - "license": "ISC", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dependencies": { "wrappy": "1" } }, "node_modules/openapi-typescript": { "version": "4.5.0", + "resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-4.5.0.tgz", + "integrity": "sha512-++gWZLTKmbZP608JHMerllAs84HzULWfVjfH7otkWBLrKxUvzHMFqI6R4JSW1LoNDZnS4KKiRTZW66Fxyp6z4Q==", "dev": true, - "license": "MIT", "dependencies": { "hosted-git-info": "^3.0.8", "js-yaml": "^4.1.0", @@ -7656,8 +8094,9 @@ }, "node_modules/optionator": { "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, - "license": "MIT", "dependencies": { "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", @@ -7670,15 +8109,11 @@ "node": ">= 0.8.0" } }, - "node_modules/os-browserify": { - "version": "0.3.0", - "dev": true, - "license": "MIT" - }, "node_modules/p-limit": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, - "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -7691,8 +8126,9 @@ }, "node_modules/p-locate": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, - "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -7702,20 +8138,17 @@ }, "node_modules/p-try": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/pako": { - "version": "1.0.11", - "dev": true, - "license": "(MIT AND Zlib)" - }, "node_modules/parent-module": { "version": "1.0.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dependencies": { "callsites": "^3.0.0" }, @@ -7723,22 +8156,11 @@ "node": ">=6" } }, - "node_modules/parse-asn1": { - "version": "5.1.6", - "dev": true, - "license": "ISC", - "dependencies": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" - } - }, "node_modules/parse-entities": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz", + "integrity": "sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==", "dev": true, - "license": "MIT", "dependencies": { "@types/unist": "^2.0.0", "character-entities": "^2.0.0", @@ -7756,12 +8178,14 @@ }, "node_modules/parse-entities/node_modules/@types/unist": { "version": "2.0.10", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", + "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==", + "dev": true }, "node_modules/parse-json": { "version": "5.2.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -7775,42 +8199,42 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/path-browserify": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, "node_modules/path-exists": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/path-is-absolute": { "version": "1.0.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "engines": { "node": ">=0.10.0" } }, "node_modules/path-key": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/path-parse": { "version": "1.0.7", - "license": "MIT" + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-scurry": { "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", "dev": true, - "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^9.1.1 || ^10.0.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -7824,54 +8248,45 @@ }, "node_modules/path-scurry/node_modules/lru-cache": { "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", "dev": true, - "license": "ISC", "engines": { "node": "14 || >=16.14" } }, "node_modules/path-to-regexp": { "version": "1.8.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", "dependencies": { "isarray": "0.0.1" } }, "node_modules/path-to-regexp/node_modules/isarray": { "version": "0.0.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" }, "node_modules/path-type": { "version": "4.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "engines": { "node": ">=8" } }, - "node_modules/pbkdf2": { - "version": "3.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - }, - "engines": { - "node": ">=0.12" - } - }, "node_modules/pend": { "version": "1.2.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true }, "node_modules/periscopic": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", + "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^3.0.0", @@ -7880,89 +8295,25 @@ }, "node_modules/picocolors": { "version": "1.0.0", - "license": "ISC" + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "node_modules/picomatch": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pkg-dir": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^5.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "6.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, "engines": { - "node": ">=10" + "node": ">=8.6" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/postcss": { "version": "8.4.33", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", + "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", "funding": [ { "type": "opencollective", @@ -7977,7 +8328,6 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.0.0", @@ -7988,8 +8338,9 @@ } }, "node_modules/posthog-js": { - "version": "1.103.1", - "license": "MIT", + "version": "1.104.4", + "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.104.4.tgz", + "integrity": "sha512-eZyNh0mhyfC129udFh5ln1QnUy67cPnRITVFvcOK4hdniM1v+T+cPxAkQK+4CjdHvvLM8hjh6OhiMWfppYqUzA==", "dependencies": { "fflate": "^0.4.8", "preact": "^10.19.3" @@ -7997,7 +8348,8 @@ }, "node_modules/preact": { "version": "10.19.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.19.3.tgz", + "integrity": "sha512-nHHTeFVBTHRGxJXKkKu5hT8C/YWBkPso4/Gad6xuj5dbptt9iF9NZr9pHbPhBrnT2klheu7mHTxTZ/LjwJiEiQ==", "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" @@ -8005,16 +8357,18 @@ }, "node_modules/prelude-ls": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8.0" } }, "node_modules/prettier": { "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true, - "license": "MIT", "bin": { "prettier": "bin-prettier.js" }, @@ -8027,8 +8381,9 @@ }, "node_modules/prettier-linter-helpers": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", "dev": true, - "license": "MIT", "dependencies": { "fast-diff": "^1.1.2" }, @@ -8038,8 +8393,9 @@ }, "node_modules/pretty-format": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -8051,8 +8407,9 @@ }, "node_modules/pretty-format/node_modules/ansi-styles": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -8062,12 +8419,14 @@ }, "node_modules/pretty-format/node_modules/react-is": { "version": "17.0.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true }, "node_modules/prism-react-renderer": { "version": "2.3.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-2.3.1.tgz", + "integrity": "sha512-Rdf+HzBLR7KYjzpJ1rSoxT9ioO85nZngQEoFIhL07XhtJHlCU3SOz0GJ6+qvMyQe0Se+BV3qpe6Yd/NmQF5Juw==", "dependencies": { "@types/prismjs": "^1.26.0", "clsx": "^2.0.0" @@ -8078,30 +8437,25 @@ }, "node_modules/prism-react-renderer/node_modules/clsx": { "version": "2.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", "engines": { "node": ">=6" } }, - "node_modules/process": { - "version": "0.11.10", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/progress": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.4.0" } }, "node_modules/prop-types": { "version": "15.8.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -8110,81 +8464,46 @@ }, "node_modules/prop-types/node_modules/react-is": { "version": "16.13.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/property-expr": { "version": "2.0.6", - "license": "MIT" + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", + "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==" }, "node_modules/property-information": { "version": "6.4.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.4.1.tgz", + "integrity": "sha512-OHYtXfu5aI2sS2LWFSN5rgJjrQ4pCy8i1jubJLe2QvMF8JJ++HXTUIVWFLfXJoaOfvYYjk2SN8J2wFUWIGXT4w==", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/public-encrypt": { - "version": "4.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/public-encrypt/node_modules/bn.js": { - "version": "4.12.0", - "dev": true, - "license": "MIT" - }, "node_modules/punycode": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/pure-color": { - "version": "1.3.0", - "license": "MIT" - }, "node_modules/qr.js": { "version": "0.0.0", - "license": "MIT" - }, - "node_modules/qs": { - "version": "6.11.2", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/querystring-es3": { - "version": "0.2.1", - "dev": true, - "engines": { - "node": ">=0.4.x" - } + "resolved": "https://registry.npmjs.org/qr.js/-/qr.js-0.0.0.tgz", + "integrity": "sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ==" }, "node_modules/querystringify": { "version": "2.2.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" }, "node_modules/queue-microtask": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, "funding": [ { @@ -8199,37 +8518,21 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" + ] }, "node_modules/quick-lru": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/randombytes": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/randomfill": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, "node_modules/react": { "version": "17.0.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -8240,7 +8543,8 @@ }, "node_modules/react-codemirror2": { "version": "7.3.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/react-codemirror2/-/react-codemirror2-7.3.0.tgz", + "integrity": "sha512-gCgJPXDX+5iaPolkHAu1YbJ92a2yL7Je4TuyO3QEqOtI/d6mbEk08l0oIm18R4ctuT/Sl87X63xIMBnRQBXYXA==", "peerDependencies": { "codemirror": "5.x", "react": ">=15.5 <=17.x" @@ -8248,7 +8552,8 @@ }, "node_modules/react-cropper": { "version": "2.3.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/react-cropper/-/react-cropper-2.3.3.tgz", + "integrity": "sha512-zghiEYkUb41kqtu+2jpX2Ntigf+Jj1dF9ew4lAobPzI2adaPE31z0p+5TcWngK6TvmWQUwK3lj4G+NDh1PDQ1w==", "dependencies": { "cropperjs": "^1.5.13" }, @@ -8256,44 +8561,10 @@ "react": ">=17.0.2" } }, - "node_modules/react-dnd": { - "version": "14.0.5", - "license": "MIT", - "dependencies": { - "@react-dnd/invariant": "^2.0.0", - "@react-dnd/shallowequal": "^2.0.0", - "dnd-core": "14.0.1", - "fast-deep-equal": "^3.1.3", - "hoist-non-react-statics": "^3.3.2" - }, - "peerDependencies": { - "@types/hoist-non-react-statics": ">= 3.3.1", - "@types/node": ">= 12", - "@types/react": ">= 16", - "react": ">= 16.14" - }, - "peerDependenciesMeta": { - "@types/hoist-non-react-statics": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-dnd-html5-backend": { - "version": "14.1.0", - "license": "MIT", - "dependencies": { - "dnd-core": "14.0.1" - } - }, "node_modules/react-dom": { "version": "17.0.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", @@ -8305,7 +8576,8 @@ }, "node_modules/react-dom/node_modules/scheduler": { "version": "0.20.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -8313,7 +8585,8 @@ }, "node_modules/react-draggable": { "version": "4.4.6", - "license": "MIT", + "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.6.tgz", + "integrity": "sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==", "dependencies": { "clsx": "^1.1.1", "prop-types": "^15.8.1" @@ -8325,11 +8598,13 @@ }, "node_modules/react-fast-compare": { "version": "2.0.4", - "license": "MIT" + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz", + "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==" }, "node_modules/react-google-recaptcha-v3": { "version": "1.9.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/react-google-recaptcha-v3/-/react-google-recaptcha-v3-1.9.5.tgz", + "integrity": "sha512-WmrhBMCnJovUPdA5S+9SmYlPTPIDXmUJWlHlOnJAXdU0cyZcVkqwln3kIj/NLl8Y6HH/4lKgno5N/e1N+fEtfg==", "dependencies": { "hoist-non-react-statics": "^3.3.2" }, @@ -8340,11 +8615,13 @@ }, "node_modules/react-gtm-module": { "version": "2.0.11", - "license": "MIT" + "resolved": "https://registry.npmjs.org/react-gtm-module/-/react-gtm-module-2.0.11.tgz", + "integrity": "sha512-8gyj4TTxeP7eEyc2QKawEuQoAZdjKvMY4pgWfycGmqGByhs17fR+zEBs0JUDq4US/l+vbTl+6zvUIx27iDo/Vw==" }, "node_modules/react-helmet": { "version": "6.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-6.1.0.tgz", + "integrity": "sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==", "dependencies": { "object-assign": "^4.1.1", "prop-types": "^15.7.2", @@ -8357,19 +8634,23 @@ }, "node_modules/react-helmet/node_modules/react-fast-compare": { "version": "3.2.2", - "license": "MIT" + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" }, "node_modules/react-is": { "version": "18.2.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, "node_modules/react-lifecycles-compat": { "version": "3.0.4", - "license": "MIT" + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, "node_modules/react-list": { "version": "0.8.17", - "license": "MIT", + "resolved": "https://registry.npmjs.org/react-list/-/react-list-0.8.17.tgz", + "integrity": "sha512-pgmzGi0G5uGrdHzMhgO7KR1wx5ZXVvI3SsJUmkblSAKtewIhMwbQiMuQiTE83ozo04BQJbe0r3WIWzSO0dR1xg==", "dependencies": { "prop-types": "15" }, @@ -8379,7 +8660,8 @@ }, "node_modules/react-markdown": { "version": "8.0.7", - "license": "MIT", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-8.0.7.tgz", + "integrity": "sha512-bvWbzG4MtOU62XqBx3Xx+zB2raaFFsq4mYiAzfjXJMEz2sixgeAfraA3tvzULF02ZdOMUOKTBFFaZJDDrq+BJQ==", "dependencies": { "@types/hast": "^2.0.0", "@types/prop-types": "^15.0.0", @@ -8407,26 +8689,30 @@ } }, "node_modules/react-markdown/node_modules/@types/hast": { - "version": "2.3.9", - "license": "MIT", + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", + "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", "dependencies": { "@types/unist": "^2" } }, "node_modules/react-markdown/node_modules/@types/mdast": { "version": "3.0.15", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz", + "integrity": "sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==", "dependencies": { "@types/unist": "^2" } }, "node_modules/react-markdown/node_modules/@types/unist": { "version": "2.0.10", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", + "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==" }, "node_modules/react-markdown/node_modules/hast-util-whitespace": { "version": "2.0.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz", + "integrity": "sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==", "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" @@ -8434,6 +8720,8 @@ }, "node_modules/react-markdown/node_modules/is-buffer": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", "funding": [ { "type": "github", @@ -8448,14 +8736,14 @@ "url": "https://feross.org/support" } ], - "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/react-markdown/node_modules/is-plain-obj": { "version": "4.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "engines": { "node": ">=12" }, @@ -8465,7 +8753,8 @@ }, "node_modules/react-markdown/node_modules/mdast-util-from-markdown": { "version": "1.3.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz", + "integrity": "sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==", "dependencies": { "@types/mdast": "^3.0.0", "@types/unist": "^2.0.0", @@ -8487,7 +8776,8 @@ }, "node_modules/react-markdown/node_modules/mdast-util-to-hast": { "version": "12.3.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-12.3.0.tgz", + "integrity": "sha512-pits93r8PhnIoU4Vy9bjW39M2jJ6/tdHyja9rrot9uujkN7UTU9SDnE6WNJz/IGyQk3XHX6yNNtrBH6cQzm8Hw==", "dependencies": { "@types/hast": "^2.0.0", "@types/mdast": "^3.0.0", @@ -8505,7 +8795,8 @@ }, "node_modules/react-markdown/node_modules/mdast-util-to-string": { "version": "3.2.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz", + "integrity": "sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==", "dependencies": { "@types/mdast": "^3.0.0" }, @@ -8516,6 +8807,8 @@ }, "node_modules/react-markdown/node_modules/micromark": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.2.0.tgz", + "integrity": "sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==", "funding": [ { "type": "GitHub Sponsors", @@ -8526,7 +8819,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", @@ -8549,6 +8841,8 @@ }, "node_modules/react-markdown/node_modules/micromark-core-commonmark": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz", + "integrity": "sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==", "funding": [ { "type": "GitHub Sponsors", @@ -8559,7 +8853,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "decode-named-character-reference": "^1.0.0", "micromark-factory-destination": "^1.0.0", @@ -8581,6 +8874,8 @@ }, "node_modules/react-markdown/node_modules/micromark-factory-destination": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.1.0.tgz", + "integrity": "sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==", "funding": [ { "type": "GitHub Sponsors", @@ -8591,7 +8886,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-util-character": "^1.0.0", "micromark-util-symbol": "^1.0.0", @@ -8600,6 +8894,8 @@ }, "node_modules/react-markdown/node_modules/micromark-factory-label": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.1.0.tgz", + "integrity": "sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==", "funding": [ { "type": "GitHub Sponsors", @@ -8610,7 +8906,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-util-character": "^1.0.0", "micromark-util-symbol": "^1.0.0", @@ -8620,6 +8915,8 @@ }, "node_modules/react-markdown/node_modules/micromark-factory-space": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz", + "integrity": "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==", "funding": [ { "type": "GitHub Sponsors", @@ -8630,7 +8927,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-util-character": "^1.0.0", "micromark-util-types": "^1.0.0" @@ -8638,6 +8934,8 @@ }, "node_modules/react-markdown/node_modules/micromark-factory-title": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.1.0.tgz", + "integrity": "sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==", "funding": [ { "type": "GitHub Sponsors", @@ -8648,7 +8946,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-factory-space": "^1.0.0", "micromark-util-character": "^1.0.0", @@ -8658,6 +8955,8 @@ }, "node_modules/react-markdown/node_modules/micromark-factory-whitespace": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.1.0.tgz", + "integrity": "sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==", "funding": [ { "type": "GitHub Sponsors", @@ -8668,7 +8967,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-factory-space": "^1.0.0", "micromark-util-character": "^1.0.0", @@ -8678,6 +8976,8 @@ }, "node_modules/react-markdown/node_modules/micromark-util-character": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz", + "integrity": "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==", "funding": [ { "type": "GitHub Sponsors", @@ -8688,7 +8988,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.0" @@ -8696,6 +8995,8 @@ }, "node_modules/react-markdown/node_modules/micromark-util-chunked": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz", + "integrity": "sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==", "funding": [ { "type": "GitHub Sponsors", @@ -8706,13 +9007,14 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-util-symbol": "^1.0.0" } }, "node_modules/react-markdown/node_modules/micromark-util-classify-character": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz", + "integrity": "sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==", "funding": [ { "type": "GitHub Sponsors", @@ -8723,7 +9025,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-util-character": "^1.0.0", "micromark-util-symbol": "^1.0.0", @@ -8732,6 +9033,8 @@ }, "node_modules/react-markdown/node_modules/micromark-util-combine-extensions": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.1.0.tgz", + "integrity": "sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==", "funding": [ { "type": "GitHub Sponsors", @@ -8742,7 +9045,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-util-chunked": "^1.0.0", "micromark-util-types": "^1.0.0" @@ -8750,6 +9052,8 @@ }, "node_modules/react-markdown/node_modules/micromark-util-decode-numeric-character-reference": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.1.0.tgz", + "integrity": "sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==", "funding": [ { "type": "GitHub Sponsors", @@ -8760,13 +9064,14 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-util-symbol": "^1.0.0" } }, "node_modules/react-markdown/node_modules/micromark-util-decode-string": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.1.0.tgz", + "integrity": "sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==", "funding": [ { "type": "GitHub Sponsors", @@ -8777,7 +9082,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "decode-named-character-reference": "^1.0.0", "micromark-util-character": "^1.0.0", @@ -8787,6 +9091,8 @@ }, "node_modules/react-markdown/node_modules/micromark-util-encode": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz", + "integrity": "sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==", "funding": [ { "type": "GitHub Sponsors", @@ -8796,11 +9102,12 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ], - "license": "MIT" + ] }, "node_modules/react-markdown/node_modules/micromark-util-html-tag-name": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.2.0.tgz", + "integrity": "sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==", "funding": [ { "type": "GitHub Sponsors", @@ -8810,11 +9117,12 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ], - "license": "MIT" + ] }, "node_modules/react-markdown/node_modules/micromark-util-normalize-identifier": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz", + "integrity": "sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==", "funding": [ { "type": "GitHub Sponsors", @@ -8825,13 +9133,14 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-util-symbol": "^1.0.0" } }, "node_modules/react-markdown/node_modules/micromark-util-resolve-all": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz", + "integrity": "sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==", "funding": [ { "type": "GitHub Sponsors", @@ -8842,13 +9151,14 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-util-types": "^1.0.0" } }, "node_modules/react-markdown/node_modules/micromark-util-sanitize-uri": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz", + "integrity": "sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==", "funding": [ { "type": "GitHub Sponsors", @@ -8859,7 +9169,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-util-character": "^1.0.0", "micromark-util-encode": "^1.0.0", @@ -8868,6 +9177,8 @@ }, "node_modules/react-markdown/node_modules/micromark-util-subtokenize": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz", + "integrity": "sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==", "funding": [ { "type": "GitHub Sponsors", @@ -8878,7 +9189,6 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", "dependencies": { "micromark-util-chunked": "^1.0.0", "micromark-util-symbol": "^1.0.0", @@ -8888,6 +9198,8 @@ }, "node_modules/react-markdown/node_modules/micromark-util-symbol": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz", + "integrity": "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==", "funding": [ { "type": "GitHub Sponsors", @@ -8897,11 +9209,12 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ], - "license": "MIT" + ] }, "node_modules/react-markdown/node_modules/micromark-util-types": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", "funding": [ { "type": "GitHub Sponsors", @@ -8911,12 +9224,12 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ], - "license": "MIT" + ] }, "node_modules/react-markdown/node_modules/remark-parse": { "version": "10.0.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.2.tgz", + "integrity": "sha512-3ydxgHa/ZQzG8LvC7jTXccARYDcRld3VfcgIIFs7bI6vbRSxJJmzgLEIIoYKyrfhaY+ujuWaf/PJiMZXoiCXgw==", "dependencies": { "@types/mdast": "^3.0.0", "mdast-util-from-markdown": "^1.0.0", @@ -8929,7 +9242,8 @@ }, "node_modules/react-markdown/node_modules/remark-rehype": { "version": "10.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-10.1.0.tgz", + "integrity": "sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw==", "dependencies": { "@types/hast": "^2.0.0", "@types/mdast": "^3.0.0", @@ -8943,7 +9257,8 @@ }, "node_modules/react-markdown/node_modules/unified": { "version": "10.1.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", "dependencies": { "@types/unist": "^2.0.0", "bail": "^2.0.0", @@ -8960,7 +9275,8 @@ }, "node_modules/react-markdown/node_modules/unist-util-is": { "version": "5.2.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", "dependencies": { "@types/unist": "^2.0.0" }, @@ -8971,7 +9287,8 @@ }, "node_modules/react-markdown/node_modules/unist-util-position": { "version": "4.0.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-4.0.4.tgz", + "integrity": "sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg==", "dependencies": { "@types/unist": "^2.0.0" }, @@ -8982,7 +9299,8 @@ }, "node_modules/react-markdown/node_modules/unist-util-stringify-position": { "version": "3.0.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", "dependencies": { "@types/unist": "^2.0.0" }, @@ -8993,7 +9311,8 @@ }, "node_modules/react-markdown/node_modules/unist-util-visit": { "version": "4.1.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", + "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==", "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0", @@ -9006,7 +9325,8 @@ }, "node_modules/react-markdown/node_modules/unist-util-visit-parents": { "version": "5.1.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", + "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0" @@ -9018,7 +9338,8 @@ }, "node_modules/react-markdown/node_modules/vfile": { "version": "5.3.7", - "license": "MIT", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", + "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", "dependencies": { "@types/unist": "^2.0.0", "is-buffer": "^2.0.0", @@ -9032,7 +9353,8 @@ }, "node_modules/react-markdown/node_modules/vfile-message": { "version": "3.1.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", + "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", "dependencies": { "@types/unist": "^2.0.0", "unist-util-stringify-position": "^3.0.0" @@ -9044,7 +9366,8 @@ }, "node_modules/react-qr-code": { "version": "2.0.12", - "license": "MIT", + "resolved": "https://registry.npmjs.org/react-qr-code/-/react-qr-code-2.0.12.tgz", + "integrity": "sha512-k+pzP5CKLEGBRwZsDPp98/CAJeXlsYRHM2iZn1Sd5Th/HnKhIZCSg27PXO58zk8z02RaEryg+60xa4vyywMJwg==", "dependencies": { "prop-types": "^15.8.1", "qr.js": "0.0.0" @@ -9061,7 +9384,8 @@ }, "node_modules/react-query": { "version": "3.39.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/react-query/-/react-query-3.39.3.tgz", + "integrity": "sha512-nLfLz7GiohKTJDuT4us4X3h/8unOh+00MLb2yJoGTPjxKs2bc1iDhkNx2bd5MKklXnOD3NrVZ+J2UXujA5In4g==", "dependencies": { "@babel/runtime": "^7.5.5", "broadcast-channel": "^3.4.1", @@ -9085,7 +9409,8 @@ }, "node_modules/react-redux": { "version": "7.2.9", - "license": "MIT", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", + "integrity": "sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==", "dependencies": { "@babel/runtime": "^7.15.4", "@types/react-redux": "^7.1.20", @@ -9108,18 +9433,21 @@ }, "node_modules/react-redux/node_modules/react-is": { "version": "17.0.2", - "license": "MIT" + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "node_modules/react-refresh": { "version": "0.14.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", + "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", "engines": { "node": ">=0.10.0" } }, "node_modules/react-router": { "version": "5.3.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", + "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", "dependencies": { "@babel/runtime": "^7.12.13", "history": "^4.9.0", @@ -9137,7 +9465,8 @@ }, "node_modules/react-router-dom": { "version": "5.3.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz", + "integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==", "dependencies": { "@babel/runtime": "^7.12.13", "history": "^4.9.0", @@ -9153,18 +9482,21 @@ }, "node_modules/react-router/node_modules/react-is": { "version": "16.13.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/react-side-effect": { "version": "2.1.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.2.tgz", + "integrity": "sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw==", "peerDependencies": { "react": "^16.3.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/react-smooth": { "version": "2.0.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-2.0.5.tgz", + "integrity": "sha512-BMP2Ad42tD60h0JW6BFaib+RJuV5dsXJK9Baxiv/HlNFjvRLqA9xrNKxVWnUIZPQfzUwGXIlU/dSYLU+54YGQA==", "dependencies": { "fast-equals": "^5.0.0", "react-transition-group": "2.9.0" @@ -9177,14 +9509,16 @@ }, "node_modules/react-smooth/node_modules/dom-helpers": { "version": "3.4.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", + "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==", "dependencies": { "@babel/runtime": "^7.1.2" } }, "node_modules/react-smooth/node_modules/react-transition-group": { "version": "2.9.0", - "license": "BSD-3-Clause", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", + "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==", "dependencies": { "dom-helpers": "^3.4.0", "loose-envify": "^1.4.0", @@ -9198,7 +9532,8 @@ }, "node_modules/react-transition-group": { "version": "4.4.5", - "license": "BSD-3-Clause", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", @@ -9212,8 +9547,9 @@ }, "node_modules/read-pkg": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", "dev": true, - "license": "MIT", "dependencies": { "@types/normalize-package-data": "^2.4.0", "normalize-package-data": "^2.5.0", @@ -9226,8 +9562,9 @@ }, "node_modules/read-pkg-up": { "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", "dev": true, - "license": "MIT", "dependencies": { "find-up": "^4.1.0", "read-pkg": "^5.2.0", @@ -9242,21 +9579,24 @@ }, "node_modules/read-pkg-up/node_modules/type-fest": { "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true, - "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=8" } }, "node_modules/read-pkg/node_modules/hosted-git-info": { "version": "2.8.9", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true }, "node_modules/read-pkg/node_modules/normalize-package-data": { "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", @@ -9266,37 +9606,27 @@ }, "node_modules/read-pkg/node_modules/semver": { "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver" } }, "node_modules/read-pkg/node_modules/type-fest": { "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", "dev": true, - "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=8" } }, - "node_modules/readable-stream": { - "version": "3.6.2", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/readdirp": { "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, - "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -9306,7 +9636,8 @@ }, "node_modules/recharts": { "version": "2.11.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.11.0.tgz", + "integrity": "sha512-5s+u1m5Hwxb2nh0LABkE3TS/lFqFHyWl7FnPbQhHobbQQia4ih1t3o3+ikPYr31Ns+kYe4FASIthKeKi/YYvMg==", "dependencies": { "clsx": "^2.0.0", "eventemitter3": "^4.0.1", @@ -9328,26 +9659,30 @@ }, "node_modules/recharts-scale": { "version": "0.4.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", "dependencies": { "decimal.js-light": "^2.4.1" } }, "node_modules/recharts/node_modules/clsx": { "version": "2.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", "engines": { "node": ">=6" } }, "node_modules/recharts/node_modules/react-is": { "version": "16.13.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/redent": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", "dev": true, - "license": "MIT", "dependencies": { "indent-string": "^4.0.0", "strip-indent": "^3.0.0" @@ -9358,46 +9693,44 @@ }, "node_modules/redux": { "version": "4.2.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", "dependencies": { "@babel/runtime": "^7.9.2" } }, - "node_modules/redux-devtools-extension": { - "version": "2.13.9", - "dev": true, - "license": "MIT", - "peerDependencies": { - "redux": "^3.1.0 || ^4.0.0" - } - }, "node_modules/redux-promise-middleware": { "version": "6.2.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/redux-promise-middleware/-/redux-promise-middleware-6.2.0.tgz", + "integrity": "sha512-TEzfMeLX63gju2WqkdFQlQMvUGYzFvJNePIJJsBlbPHs3Txsbc/5Rjhmtha1XdMU6lkeiIlp1Qx7AR3Zo9he9g==", "peerDependencies": { "redux": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0" } }, "node_modules/redux-thunk": { "version": "2.4.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", + "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", "peerDependencies": { "redux": "^4" } }, "node_modules/reflect-metadata": { "version": "0.1.14", - "license": "Apache-2.0" + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", + "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==" }, "node_modules/reflect.getprototypeof": { - "version": "1.0.4", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.5.tgz", + "integrity": "sha512-62wgfC8dJWrmxv44CA36pLDnP6KKl3Vhxb7PL+8+qrrFMMoJij4vgiMP8zV4O8+CBMXY1mHxI5fITGHXFHVmQQ==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.0.0", + "get-intrinsic": "^1.2.3", "globalthis": "^1.0.3", "which-builtin-type": "^1.1.3" }, @@ -9410,12 +9743,14 @@ }, "node_modules/regenerator-runtime": { "version": "0.13.11", - "license": "MIT" + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, "node_modules/regexp.prototype.flags": { "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -9430,8 +9765,9 @@ }, "node_modules/regexpp": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" }, @@ -9441,8 +9777,9 @@ }, "node_modules/rehype-highlight": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-highlight/-/rehype-highlight-7.0.0.tgz", + "integrity": "sha512-QtobgRgYoQaK6p1eSr2SD1i61f7bjF2kZHAQHxeCHAuJf7ZUDMvQ7owDq9YTkmar5m5TSUol+2D3bp3KfJf/oA==", "dev": true, - "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "hast-util-to-text": "^4.0.0", @@ -9457,8 +9794,9 @@ }, "node_modules/remark-mdx": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.0.0.tgz", + "integrity": "sha512-O7yfjuC6ra3NHPbRVxfflafAj3LTwx3b73aBvkEFU5z4PsD6FD4vrqJAkE5iNGLz71GdjXfgRqm3SQ0h0VuE7g==", "dev": true, - "license": "MIT", "dependencies": { "mdast-util-mdx": "^3.0.0", "micromark-extension-mdxjs": "^3.0.0" @@ -9470,8 +9808,9 @@ }, "node_modules/remark-parse": { "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", "dev": true, - "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", @@ -9485,8 +9824,9 @@ }, "node_modules/remark-rehype": { "version": "11.1.0", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.0.tgz", + "integrity": "sha512-z3tJrAs2kIs1AqIIy6pzHmAHlF1hWQ+OdY4/hv+Wxe35EhyLKcajL33iUEn3ScxtFox9nUvRufR/Zre8Q08H/g==", "dev": true, - "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", @@ -9501,30 +9841,27 @@ }, "node_modules/remove-accents": { "version": "0.5.0", - "license": "MIT" - }, - "node_modules/rename-keys": { - "version": "1.2.0", - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } + "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz", + "integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==" }, "node_modules/require-from-string": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/requires-port": { "version": "1.0.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, "node_modules/resolve": { "version": "1.22.8", - "license": "MIT", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -9539,19 +9876,22 @@ }, "node_modules/resolve-from": { "version": "4.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "engines": { "node": ">=4" } }, "node_modules/resolve-pathname": { "version": "3.0.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" }, "node_modules/reusify": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, - "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -9559,14 +9899,16 @@ }, "node_modules/rifm": { "version": "0.12.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/rifm/-/rifm-0.12.1.tgz", + "integrity": "sha512-OGA1Bitg/dSJtI/c4dh90svzaUPt228kzFsUkJbtA2c964IqEAwWXeL9ZJi86xWv3j5SMqRvGULl7bA6cK0Bvg==", "peerDependencies": { "react": ">=16.8" } }, "node_modules/rimraf": { "version": "3.0.2", - "license": "ISC", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dependencies": { "glob": "^7.1.3" }, @@ -9579,7 +9921,8 @@ }, "node_modules/rimraf/node_modules/brace-expansion": { "version": "1.1.11", - "license": "MIT", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -9587,7 +9930,8 @@ }, "node_modules/rimraf/node_modules/glob": { "version": "7.2.3", - "license": "ISC", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -9605,7 +9949,8 @@ }, "node_modules/rimraf/node_modules/minimatch": { "version": "3.1.2", - "license": "ISC", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -9613,18 +9958,11 @@ "node": "*" } }, - "node_modules/ripemd160": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, "node_modules/rollup": { + "name": "@rollup/wasm-node", "version": "4.9.6", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@rollup/wasm-node/-/wasm-node-4.9.6.tgz", + "integrity": "sha512-B3FpAkroTE6q+MRHzv8XLBgPbxdjJiy5UnduZNQ/4lxeF1JT2O/OAr0JPpXeRG/7zpKm/kdqU/4m6AULhmnSqw==", "dependencies": { "@types/estree": "1.0.5" }, @@ -9636,24 +9974,13 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.9.6", - "@rollup/rollup-android-arm64": "4.9.6", - "@rollup/rollup-darwin-arm64": "4.9.6", - "@rollup/rollup-darwin-x64": "4.9.6", - "@rollup/rollup-linux-arm-gnueabihf": "4.9.6", - "@rollup/rollup-linux-arm64-gnu": "4.9.6", - "@rollup/rollup-linux-arm64-musl": "4.9.6", - "@rollup/rollup-linux-riscv64-gnu": "4.9.6", - "@rollup/rollup-linux-x64-gnu": "4.9.6", - "@rollup/rollup-linux-x64-musl": "4.9.6", - "@rollup/rollup-win32-arm64-msvc": "4.9.6", - "@rollup/rollup-win32-ia32-msvc": "4.9.6", - "@rollup/rollup-win32-x64-msvc": "4.9.6", "fsevents": "~2.3.2" } }, "node_modules/run-parallel": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, "funding": [ { @@ -9669,14 +9996,14 @@ "url": "https://feross.org/support" } ], - "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } }, "node_modules/sade": { "version": "1.8.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", "dependencies": { "mri": "^1.1.0" }, @@ -9686,8 +10013,9 @@ }, "node_modules/safe-array-concat": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", + "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.5", "get-intrinsic": "^1.2.2", @@ -9703,6 +10031,8 @@ }, "node_modules/safe-buffer": { "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "funding": [ { "type": "github", @@ -9716,13 +10046,13 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" + ] }, "node_modules/safe-regex-test": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.2.tgz", + "integrity": "sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.5", "get-intrinsic": "^1.2.2", @@ -9735,23 +10065,20 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "dev": true, - "license": "MIT" - }, "node_modules/scheduler": { "version": "0.23.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", "peer": true, "dependencies": { "loose-envify": "^1.1.0" } }, "node_modules/semver": { - "version": "7.5.4", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dev": true, - "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -9764,8 +10091,9 @@ }, "node_modules/semver/node_modules/lru-cache": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, - "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -9775,13 +10103,15 @@ }, "node_modules/semver/node_modules/yallist": { "version": "4.0.0", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/set-function-length": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz", + "integrity": "sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==", "dev": true, - "license": "MIT", "dependencies": { "define-data-property": "^1.1.1", "function-bind": "^1.1.2", @@ -9795,8 +10125,9 @@ }, "node_modules/set-function-name": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", "dev": true, - "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", "functions-have-names": "^1.2.3", @@ -9806,27 +10137,11 @@ "node": ">= 0.4" } }, - "node_modules/setimmediate": { - "version": "1.0.5", - "dev": true, - "license": "MIT" - }, - "node_modules/sha.js": { - "version": "2.4.11", - "dev": true, - "license": "(MIT AND BSD-3-Clause)", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - }, - "bin": { - "sha.js": "bin.js" - } - }, "node_modules/shebang-command": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, - "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -9836,16 +10151,18 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/side-channel": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -9857,8 +10174,9 @@ }, "node_modules/signal-exit": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, - "license": "ISC", "engines": { "node": ">=14" }, @@ -9868,16 +10186,18 @@ }, "node_modules/slash": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/slice-ansi": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", @@ -9892,8 +10212,9 @@ }, "node_modules/snake-case": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", "dev": true, - "license": "MIT", "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" @@ -9901,7 +10222,8 @@ }, "node_modules/sockjs-client": { "version": "1.6.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.6.1.tgz", + "integrity": "sha512-2g0tjOR+fRs0amxENLi/q5TiJTqY+WXFOzb5UwXndlK6TO3U/mirZznpx6w34HVMoc3g7cY24yC/ZMIYnDlfkw==", "dependencies": { "debug": "^3.2.7", "eventsource": "^2.0.2", @@ -9918,28 +10240,32 @@ }, "node_modules/sockjs-client/node_modules/debug": { "version": "3.2.7", - "license": "MIT", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dependencies": { "ms": "^2.1.1" } }, "node_modules/source-map": { "version": "0.5.7", - "license": "BSD-3-Clause", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "engines": { "node": ">=0.10.0" } }, "node_modules/source-map-js": { "version": "1.0.2", - "license": "BSD-3-Clause", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "engines": { "node": ">=0.10.0" } }, "node_modules/space-separated-tokens": { "version": "2.0.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -9947,8 +10273,9 @@ }, "node_modules/spdx-correct": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, - "license": "Apache-2.0", "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -9956,13 +10283,15 @@ }, "node_modules/spdx-exceptions": { "version": "2.4.0", - "dev": true, - "license": "CC-BY-3.0" + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.4.0.tgz", + "integrity": "sha512-hcjppoJ68fhxA/cjbN4T8N6uCUejN8yFw69ttpqtBeCbF3u13n7mb31NB9jKwGTTWWnt9IbRA/mf1FprYS8wfw==", + "dev": true }, "node_modules/spdx-expression-parse": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, - "license": "MIT", "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -9970,18 +10299,21 @@ }, "node_modules/spdx-license-ids": { "version": "3.0.16", - "dev": true, - "license": "CC0-1.0" + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", + "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", + "dev": true }, "node_modules/sprintf-js": { "version": "1.0.3", - "dev": true, - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true }, "node_modules/stop-iteration-iterator": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", "dev": true, - "license": "MIT", "dependencies": { "internal-slot": "^1.0.4" }, @@ -9989,38 +10321,11 @@ "node": ">= 0.4" } }, - "node_modules/stream-browserify": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "~2.0.4", - "readable-stream": "^3.5.0" - } - }, - "node_modules/stream-http": { - "version": "3.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "xtend": "^4.0.2" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "node_modules/string-width": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, - "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -10036,8 +10341,9 @@ "node_modules/string-width-cjs": { "name": "string-width", "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -10049,13 +10355,15 @@ }, "node_modules/string-width-cjs/node_modules/emoji-regex": { "version": "8.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true }, "node_modules/string-width/node_modules/ansi-regex": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -10065,8 +10373,9 @@ }, "node_modules/string-width/node_modules/strip-ansi": { "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -10079,8 +10388,9 @@ }, "node_modules/string.prototype.matchall": { "version": "4.0.10", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", + "integrity": "sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -10098,8 +10408,9 @@ }, "node_modules/string.prototype.trim": { "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -10114,8 +10425,9 @@ }, "node_modules/string.prototype.trimend": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -10127,8 +10439,9 @@ }, "node_modules/string.prototype.trimstart": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -10140,8 +10453,9 @@ }, "node_modules/stringify-entities": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.3.tgz", + "integrity": "sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g==", "dev": true, - "license": "MIT", "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" @@ -10153,8 +10467,9 @@ }, "node_modules/strip-ansi": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -10165,8 +10480,9 @@ "node_modules/strip-ansi-cjs": { "name": "strip-ansi", "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -10176,16 +10492,18 @@ }, "node_modules/strip-bom": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/strip-indent": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", "dev": true, - "license": "MIT", "dependencies": { "min-indent": "^1.0.0" }, @@ -10195,8 +10513,9 @@ }, "node_modules/strip-json-comments": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" }, @@ -10206,19 +10525,22 @@ }, "node_modules/style-to-object": { "version": "0.4.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.4.tgz", + "integrity": "sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==", "dependencies": { "inline-style-parser": "0.1.1" } }, "node_modules/stylis": { "version": "4.2.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" }, "node_modules/supports-color": { "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -10228,7 +10550,8 @@ }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "engines": { "node": ">= 0.4" }, @@ -10238,21 +10561,15 @@ }, "node_modules/svg-parser": { "version": "2.0.4", - "dev": true, - "license": "MIT" - }, - "node_modules/svgson": { - "version": "5.3.1", - "license": "MIT", - "dependencies": { - "deep-rename-keys": "^0.2.1", - "xml-reader": "2.4.3" - } + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", + "dev": true }, "node_modules/table": { "version": "6.8.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", + "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "ajv": "^8.0.1", "lodash.truncate": "^4.4.2", @@ -10266,8 +10583,9 @@ }, "node_modules/table/node_modules/ajv": { "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, - "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -10281,18 +10599,21 @@ }, "node_modules/table/node_modules/emoji-regex": { "version": "8.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true }, "node_modules/table/node_modules/json-schema-traverse": { "version": "1.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true }, "node_modules/table/node_modules/string-width": { "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -10304,24 +10625,15 @@ }, "node_modules/text-table": { "version": "0.2.0", - "dev": true, - "license": "MIT" - }, - "node_modules/timers-browserify": { - "version": "2.0.12", - "dev": true, - "license": "MIT", - "dependencies": { - "setimmediate": "^1.0.4" - }, - "engines": { - "node": ">=0.6.0" - } + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true }, "node_modules/tiny-glob": { "version": "0.2.9", + "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", + "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", "dev": true, - "license": "MIT", "dependencies": { "globalyzer": "0.1.0", "globrex": "^0.1.2" @@ -10329,23 +10641,46 @@ }, "node_modules/tiny-invariant": { "version": "1.3.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz", + "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==" }, "node_modules/tiny-warning": { "version": "1.0.3", - "license": "MIT" + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, + "node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, + "node_modules/tmp-promise": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", + "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", + "dependencies": { + "tmp": "^0.2.0" + } }, "node_modules/to-fast-properties": { "version": "2.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "engines": { "node": ">=4" } }, "node_modules/to-regex-range": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, - "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -10355,20 +10690,24 @@ }, "node_modules/toggle-selection": { "version": "1.0.6", - "license": "MIT" + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" }, "node_modules/toposort": { "version": "2.0.2", - "license": "MIT" + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==" }, "node_modules/tr46": { "version": "0.0.3", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true }, "node_modules/trim-lines": { "version": "3.0.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -10376,26 +10715,29 @@ }, "node_modules/trim-newlines": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/trough": { - "version": "2.1.0", - "license": "MIT", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, "node_modules/ts-api-utils": { - "version": "1.0.3", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.0.tgz", + "integrity": "sha512-d+3WxW4r8WQy2cZWpNRPPGExX8ffOLGcIhheUANKbL5Sqjbhkneki76fRAWeXkaslV2etTb4tSJBSxOsH5+CJw==", "dev": true, - "license": "MIT", "engines": { - "node": ">=16.13.0" + "node": ">=18" }, "peerDependencies": { "typescript": ">=4.2.0" @@ -10403,8 +10745,9 @@ }, "node_modules/ts-unused-exports": { "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ts-unused-exports/-/ts-unused-exports-9.0.5.tgz", + "integrity": "sha512-1XAXaH2i4Al/aZO06pWDn9MUgTN0KQi+fvWudiWfHUTHAav45gzrx7Xq6JAsu6+LoMlVoyGvNvZSPW3KTjDncA==", "dev": true, - "license": "MIT", "dependencies": { "chalk": "^4.0.0", "tsconfig-paths": "^3.9.0" @@ -10426,8 +10769,9 @@ }, "node_modules/tsconfck": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.0.1.tgz", + "integrity": "sha512-7ppiBlF3UEddCLeI1JRx5m2Ryq+xk4JrZuq4EuYXykipebaq1dV0Fhgr1hb7CkmHt32QSgOZlcqVLEtHBG4/mg==", "dev": true, - "license": "MIT", "bin": { "tsconfck": "bin/tsconfck.js" }, @@ -10445,8 +10789,9 @@ }, "node_modules/tsconfig-paths": { "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, - "license": "MIT", "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", @@ -10456,8 +10801,9 @@ }, "node_modules/tsconfig-paths/node_modules/json5": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, - "license": "MIT", "dependencies": { "minimist": "^1.2.0" }, @@ -10467,17 +10813,14 @@ }, "node_modules/tslib": { "version": "2.6.2", - "license": "0BSD" - }, - "node_modules/tty-browserify": { - "version": "0.0.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/type-check": { "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, - "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -10487,8 +10830,9 @@ }, "node_modules/type-fest": { "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", "dev": true, - "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -10498,8 +10842,9 @@ }, "node_modules/typed-array-buffer": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.2.1", @@ -10511,8 +10856,9 @@ }, "node_modules/typed-array-byte-length": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "for-each": "^0.3.3", @@ -10528,8 +10874,9 @@ }, "node_modules/typed-array-byte-offset": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", "dev": true, - "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", @@ -10546,8 +10893,9 @@ }, "node_modules/typed-array-length": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "for-each": "^0.3.3", @@ -10559,8 +10907,9 @@ }, "node_modules/typescript": { "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true, - "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -10571,8 +10920,9 @@ }, "node_modules/unbox-primitive": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-bigints": "^1.0.2", @@ -10584,9 +10934,10 @@ } }, "node_modules/undici": { - "version": "5.28.2", + "version": "5.28.3", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz", + "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==", "dev": true, - "license": "MIT", "dependencies": { "@fastify/busboy": "^2.0.0" }, @@ -10596,13 +10947,15 @@ }, "node_modules/undici-types": { "version": "5.26.5", - "devOptional": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "devOptional": true }, "node_modules/unified": { "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", @@ -10619,8 +10972,9 @@ }, "node_modules/unified/node_modules/is-plain-obj": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -10630,8 +10984,9 @@ }, "node_modules/unist-util-find-after": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", + "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" @@ -10643,7 +10998,8 @@ }, "node_modules/unist-util-generated": { "version": "2.0.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-2.0.1.tgz", + "integrity": "sha512-qF72kLmPxAw0oN2fwpWIqbXAVyEqUzDHMsbtPvOudIlUzXYFIeQIuxXQCRCFh22B7cixvU0MG7m3MW8FTq/S+A==", "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" @@ -10651,8 +11007,9 @@ }, "node_modules/unist-util-is": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", "dev": true, - "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" }, @@ -10663,8 +11020,9 @@ }, "node_modules/unist-util-position": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", "dev": true, - "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" }, @@ -10675,8 +11033,9 @@ }, "node_modules/unist-util-position-from-estree": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", + "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" }, @@ -10687,8 +11046,9 @@ }, "node_modules/unist-util-remove-position": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", "dev": true, - "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-visit": "^5.0.0" @@ -10700,8 +11060,9 @@ }, "node_modules/unist-util-stringify-position": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" }, @@ -10712,8 +11073,9 @@ }, "node_modules/unist-util-visit": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", "dev": true, - "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", @@ -10726,8 +11088,9 @@ }, "node_modules/unist-util-visit-parents": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", "dev": true, - "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" @@ -10739,15 +11102,17 @@ }, "node_modules/universalify": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, - "license": "MIT", "engines": { "node": ">= 10.0.0" } }, "node_modules/unload": { "version": "2.2.0", - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/unload/-/unload-2.2.0.tgz", + "integrity": "sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==", "dependencies": { "@babel/runtime": "^7.6.2", "detect-node": "^2.0.4" @@ -10755,6 +11120,8 @@ }, "node_modules/update-browserslist-db": { "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", "funding": [ { "type": "opencollective", @@ -10769,7 +11136,6 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { "escalade": "^3.1.1", "picocolors": "^1.0.0" @@ -10783,37 +11149,26 @@ }, "node_modules/uri-js": { "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } }, - "node_modules/url": { - "version": "0.11.3", - "dev": true, - "license": "MIT", - "dependencies": { - "punycode": "^1.4.1", - "qs": "^6.11.2" - } - }, "node_modules/url-parse": { "version": "1.5.10", - "license": "MIT", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" } }, - "node_modules/url/node_modules/punycode": { - "version": "1.4.1", - "dev": true, - "license": "MIT" - }, "node_modules/use-context-selector": { "version": "1.4.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/use-context-selector/-/use-context-selector-1.4.1.tgz", + "integrity": "sha512-Io2ArvcRO+6MWIhkdfMFt+WKQX+Vb++W8DS2l03z/Vw/rz3BclKpM0ynr4LYGyU85Eke+Yx5oIhTY++QR0ZDoA==", "peerDependencies": { "react": ">=16.8.0", "react-dom": "*", @@ -10831,7 +11186,8 @@ }, "node_modules/use-debounce": { "version": "10.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/use-debounce/-/use-debounce-10.0.0.tgz", + "integrity": "sha512-XRjvlvCB46bah9IBXVnq/ACP2lxqXyZj0D9hj4K5OzNroMDpTEBg8Anuh1/UfRTRs7pLhQ+RiNxxwZu9+MVl1A==", "engines": { "node": ">= 16.0.0" }, @@ -10841,38 +11197,24 @@ }, "node_modules/use-sync-external-store": { "version": "1.2.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, - "node_modules/util": { - "version": "0.12.5", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "which-typed-array": "^1.1.2" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, "node_modules/uuid": { "version": "9.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", "bin": { "uuid": "dist/bin/uuid" } }, "node_modules/uvu": { "version": "0.5.6", - "license": "MIT", + "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", + "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", "dependencies": { "dequal": "^2.0.0", "diff": "^5.0.0", @@ -10888,13 +11230,15 @@ }, "node_modules/v8-compile-cache": { "version": "2.4.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", + "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", + "dev": true }, "node_modules/validate-npm-package-license": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, - "license": "Apache-2.0", "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -10902,12 +11246,14 @@ }, "node_modules/value-equal": { "version": "1.0.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" }, "node_modules/vfile": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", "dev": true, - "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0", @@ -10920,8 +11266,9 @@ }, "node_modules/vfile-message": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", "dev": true, - "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" @@ -10932,8 +11279,9 @@ } }, "node_modules/victory-vendor": { - "version": "36.8.2", - "license": "MIT AND ISC", + "version": "36.9.0", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.0.tgz", + "integrity": "sha512-n1A0J1xgwHb5nh56M0d8XlQabMCeTktvEqqr5WNAHspWEsVVGGaaaRg0TcQUtyC1akX0Cox1lMZdIv0Jl7o0ew==", "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", @@ -10953,7 +11301,8 @@ }, "node_modules/vite": { "version": "5.0.12", - "license": "MIT", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.12.tgz", + "integrity": "sha512-4hsnEkG3q0N4Tzf1+t6NdN9dg/L3BM+q8SWgbSPnJvrgH2kgdyzfVJwbR1ic69/4uMJJ/3dqDZZE5/WwqW8U1w==", "dependencies": { "esbuild": "^0.19.3", "postcss": "^8.4.32", @@ -11004,25 +11353,11 @@ } } }, - "node_modules/vite-plugin-node-polyfills": { - "version": "0.19.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/plugin-inject": "^5.0.5", - "node-stdlib-browser": "^1.2.0" - }, - "funding": { - "url": "https://github.com/sponsors/davidmyersdev" - }, - "peerDependencies": { - "vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0" - } - }, "node_modules/vite-plugin-static-copy": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-1.0.1.tgz", + "integrity": "sha512-3eGL4mdZoPJMDBT68pv/XKIHR4MgVolStIxxv1gIBP4R8TpHn9C9EnaU0hesqlseJ4ycLGUxckFTu/jpuJXQlA==", "dev": true, - "license": "MIT", "dependencies": { "chokidar": "^3.5.3", "fast-glob": "^3.2.11", @@ -11038,8 +11373,9 @@ }, "node_modules/vite-plugin-svgr": { "version": "4.2.0", + "resolved": "https://registry.npmjs.org/vite-plugin-svgr/-/vite-plugin-svgr-4.2.0.tgz", + "integrity": "sha512-SC7+FfVtNQk7So0XMjrrtLAbEC8qjFPifyD7+fs/E6aaNdVde6umlVVh0QuwDLdOMu7vp5RiGFsB70nj5yo0XA==", "dev": true, - "license": "MIT", "dependencies": { "@rollup/pluginutils": "^5.0.5", "@svgr/core": "^8.1.0", @@ -11051,8 +11387,9 @@ }, "node_modules/vite-tsconfig-paths": { "version": "4.3.1", + "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-4.3.1.tgz", + "integrity": "sha512-cfgJwcGOsIxXOLU/nELPny2/LUD/lcf1IbfyeKTv2bsupVbTH/xpFtdQlBmIP1GEK2CjjLxYhFfB+QODFAx5aw==", "dev": true, - "license": "MIT", "dependencies": { "debug": "^4.1.1", "globrex": "^0.1.2", @@ -11067,33 +11404,33 @@ } } }, - "node_modules/vm-browserify": { - "version": "1.1.2", - "dev": true, - "license": "MIT" - }, "node_modules/vscode-oniguruma": { "version": "1.7.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", + "dev": true }, "node_modules/vscode-textmate": { "version": "9.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-9.0.0.tgz", + "integrity": "sha512-Cl65diFGxz7gpwbav10HqiY/eVYTO1sjQpmRmV991Bj7wAoOAjGQ97PpQcXorDE2Uc4hnGWLY17xme+5t6MlSg==", + "dev": true }, "node_modules/web-vitals": { "version": "2.1.4", - "license": "Apache-2.0" + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-2.1.4.tgz", + "integrity": "sha512-sVWcwhU5mX6crfI5Vd2dC4qchyTqxV8URinzt25XqVh+bHEPGH4C3NPrNionCP7Obx59wrYEbNlw4Z8sjALzZg==" }, "node_modules/webidl-conversions": { "version": "3.0.1", - "dev": true, - "license": "BSD-2-Clause" + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true }, "node_modules/websocket-driver": { "version": "0.7.4", - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", @@ -11105,15 +11442,17 @@ }, "node_modules/websocket-extensions": { "version": "0.1.4", - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "engines": { "node": ">=0.8.0" } }, "node_modules/whatwg-url": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dev": true, - "license": "MIT", "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -11121,8 +11460,9 @@ }, "node_modules/which": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, - "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -11135,8 +11475,9 @@ }, "node_modules/which-boxed-primitive": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "dev": true, - "license": "MIT", "dependencies": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -11150,8 +11491,9 @@ }, "node_modules/which-builtin-type": { "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", "dev": true, - "license": "MIT", "dependencies": { "function.prototype.name": "^1.1.5", "has-tostringtag": "^1.0.0", @@ -11175,8 +11517,9 @@ }, "node_modules/which-collection": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", "dev": true, - "license": "MIT", "dependencies": { "is-map": "^2.0.1", "is-set": "^2.0.1", @@ -11188,15 +11531,16 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.13", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz", + "integrity": "sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==", "dev": true, - "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.4", + "available-typed-arrays": "^1.0.6", + "call-bind": "^1.0.5", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" + "has-tostringtag": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -11207,8 +11551,9 @@ }, "node_modules/wrap-ansi": { "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -11224,8 +11569,9 @@ "node_modules/wrap-ansi-cjs": { "name": "wrap-ansi", "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -11240,13 +11586,15 @@ }, "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -11258,8 +11606,9 @@ }, "node_modules/wrap-ansi/node_modules/ansi-regex": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -11269,8 +11618,9 @@ }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -11280,8 +11630,9 @@ }, "node_modules/wrap-ansi/node_modules/strip-ansi": { "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -11294,90 +11645,55 @@ }, "node_modules/wrappy": { "version": "1.0.2", - "license": "ISC" - }, - "node_modules/xml-lexer": { - "version": "0.2.2", - "license": "MIT", - "dependencies": { - "eventemitter3": "^2.0.0" - } - }, - "node_modules/xml-lexer/node_modules/eventemitter3": { - "version": "2.0.3", - "license": "MIT" - }, - "node_modules/xml-reader": { - "version": "2.4.3", - "license": "MIT", - "dependencies": { - "eventemitter3": "^2.0.0", - "xml-lexer": "^0.2.2" - } - }, - "node_modules/xml-reader/node_modules/eventemitter3": { - "version": "2.0.3", - "license": "MIT" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/xstate": { "version": "4.38.3", + "resolved": "https://registry.npmjs.org/xstate/-/xstate-4.38.3.tgz", + "integrity": "sha512-SH7nAaaPQx57dx6qvfcIgqKRXIh4L0A1iYEqim4s1u7c9VoCgzZc+63FY90AKU4ZzOC2cfJzTnpO4zK7fCUzzw==", "dev": true, - "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/xstate" } }, - "node_modules/xtend": { - "version": "4.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, "node_modules/yallist": { "version": "3.1.1", - "license": "ISC" + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "node_modules/yaml": { "version": "1.10.2", - "license": "ISC", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", "engines": { "node": ">= 6" } }, "node_modules/yargs-parser": { "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, - "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/yauzl": { "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "dev": true, - "license": "MIT", "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/yup": { "version": "0.32.11", - "license": "MIT", + "resolved": "https://registry.npmjs.org/yup/-/yup-0.32.11.tgz", + "integrity": "sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg==", "dependencies": { "@babel/runtime": "^7.15.4", "@types/lodash": "^4.14.175", @@ -11393,7 +11709,8 @@ }, "node_modules/zustand": { "version": "4.1.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.1.2.tgz", + "integrity": "sha512-gcRaKchcxFPbImrBb/BKgujOhHhik9YhVpIeP87ETT7uokEe2Szu7KkuZ9ghjtD+/KKkcrRNktR2AiLXPIbKIQ==", "dependencies": { "use-sync-external-store": "1.2.0" }, @@ -11415,8 +11732,9 @@ }, "node_modules/zwitch": { "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", "dev": true, - "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -11424,7 +11742,8 @@ }, "node_modules/zxcvbn": { "version": "4.4.2", - "license": "MIT" + "resolved": "https://registry.npmjs.org/zxcvbn/-/zxcvbn-4.4.2.tgz", + "integrity": "sha512-Bq0B+ixT/DMyG8kgX2xWcI5jUvCwqrMxSFam7m0lAf78nf04hv6lNCsyLYdyYTrCVMqNDY/206K7eExYCeSyUQ==" } } } diff --git a/webapp/package.json b/webapp/package.json index 0600293f33..eef4e59209 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -4,9 +4,9 @@ "private": true, "type": "module", "dependencies": { - "@dicebear/avatars": "4.10.2", - "@dicebear/avatars-identicon-sprites": "4.10.2", - "@dicebear/avatars-initials-sprites": "4.10.2", + "@dicebear/core": "^7.0.4", + "@dicebear/identicon": "^7.0.4", + "@dicebear/initials": "^7.0.4", "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", "@formatjs/icu-messageformat-parser": "^2.0.8", @@ -33,8 +33,6 @@ "react": "^17.0.1", "react-codemirror2": "^7.3.0", "react-cropper": "^2.3.3", - "react-dnd": "^14.0.2", - "react-dnd-html5-backend": "^14.0.0", "react-dom": "^17.0.2", "react-draggable": "^4.4.3", "react-google-recaptcha-v3": "1.9.5", @@ -102,7 +100,7 @@ "@testing-library/react": "^12.0.0", "@testing-library/user-event": "^13.2.1", "@tginternal/language-util": "^1.0.6", - "@tolgee/cli": "^1.0.1", + "@tolgee/cli": "^1.3.2", "@types/codemirror": "^5.60.2", "@types/diff": "^5.0.2", "@types/jest": "^26.0.24", @@ -121,14 +119,21 @@ "eslint-plugin-react": "^7.24.0", "openapi-typescript": "^4.0.2", "prettier": "^2.3.1", - "redux-devtools-extension": "^2.13.9", + "@redux-devtools/extension": "^3.3.0", "rehype-highlight": "^7.0.0", "ts-unused-exports": "^9.0.4", "typescript": "^5.3.3", "vite": "^5.0.12", - "vite-plugin-node-polyfills": "^0.19.0", "vite-plugin-static-copy": "^1.0.0", "vite-plugin-svgr": "^4.2.0", "vite-tsconfig-paths": "^4.2.3" + }, + "overrides": { + "vite": { + "rollup": "npm:@rollup/wasm-node" + }, + "@mdx-js/rollup": { + "rollup": "npm:@rollup/wasm-node" + } } } diff --git a/webapp/src/component/RootRouter.tsx b/webapp/src/component/RootRouter.tsx index b8f75553eb..a4609369e8 100644 --- a/webapp/src/component/RootRouter.tsx +++ b/webapp/src/component/RootRouter.tsx @@ -12,33 +12,17 @@ import { AdministrationView } from 'tg.views/administration/AdministrationView'; import { OrganizationBillingRedirect } from './security/OrganizationRedirectHandler'; import { RequirePreferredOrganization } from '../RequirePreferredOrganization'; -const LoginRouter = React.lazy( - () => import(/* webpackChunkName: "login" */ './security/Login/LoginRouter') -); -const SignUpView = React.lazy( - () => - import( - /* webpackChunkName: "sign-up-view" */ './security/SignUp/SignUpView' - ) -); +const LoginRouter = React.lazy(() => import('./security/Login/LoginRouter')); +const SignUpView = React.lazy(() => import('./security/SignUp/SignUpView')); const PasswordResetSetView = React.lazy( - () => - import( - /* webpackChunkName: "reset-password-set-view" */ './security/ResetPasswordSetView' - ) + () => import('./security/ResetPasswordSetView') ); const PasswordResetView = React.lazy( - () => - import( - /* webpackChunkName: "reset-password-view" */ './security/ResetPasswordView' - ) + () => import('./security/ResetPasswordView') ); const AcceptInvitationHandler = React.lazy( - () => - import( - /* webpackChunkName: "accept-invitation-handler" */ './security/AcceptInvitationHandler' - ) + () => import('./security/AcceptInvitationHandler') ); const RecaptchaProvider: FC = (props) => { @@ -82,12 +66,12 @@ export const RootRouter = () => ( - - - - - - + + + + + + diff --git a/webapp/src/component/common/avatar/useAutoAvatarImgSrc.tsx b/webapp/src/component/common/avatar/useAutoAvatarImgSrc.tsx index b43e4c8b42..f14121cec0 100644 --- a/webapp/src/component/common/avatar/useAutoAvatarImgSrc.tsx +++ b/webapp/src/component/common/avatar/useAutoAvatarImgSrc.tsx @@ -1,16 +1,61 @@ import { useEffect, useState } from 'react'; import { AutoAvatarProps } from './AutoAvatar'; +import { colors } from '@mui/material'; + +const COLORS_LIGHT = [ + colors.amber[300], + colors.blue[300], + colors.blueGrey[300], + colors.brown[300], + colors.common[300], + colors.cyan[300], + colors.deepOrange[300], + colors.deepPurple[300], + colors.green[300], + colors.grey[300], + colors.indigo[300], + colors.lightBlue[300], + colors.lightGreen[300], + colors.lime[300], + colors.orange[300], + colors.pink[300], + colors.purple[300], + colors.red[300], + colors.teal[300], +]; + +const COLORS_DARK = [ + colors.amber[700], + colors.blue[700], + colors.blueGrey[700], + colors.brown[700], + colors.common[700], + colors.cyan[700], + colors.deepOrange[700], + colors.deepPurple[700], + colors.green[700], + colors.grey[700], + colors.indigo[700], + colors.lightBlue[700], + colors.lightGreen[700], + colors.lime[700], + colors.orange[700], + colors.pink[700], + colors.purple[700], + colors.red[700], + colors.teal[700], +]; function getInitialsAvatarSvg(ownerName: string, size: number, light: boolean) { return Promise.all([ importCreateAvatarFunction(), - import('@dicebear/avatars-initials-sprites'), + import('@dicebear/initials'), ]).then(([crateAvatar, style]) => { return crateAvatar(style, { seed: ownerName, size, scale: 100, - backgroundColorLevel: light ? 300 : 700, + backgroundColor: light ? COLORS_LIGHT : COLORS_DARK, }); }); } @@ -18,7 +63,7 @@ function getInitialsAvatarSvg(ownerName: string, size: number, light: boolean) { function getIdenticonAvatarSvg(entityId: number | string, size: number) { return Promise.all([ importCreateAvatarFunction(), - import('@dicebear/avatars-identicon-sprites'), + import('@dicebear/identicon'), ]).then(([crateAvatar, style]) => { return crateAvatar(style, { seed: entityId.toString(), @@ -29,7 +74,7 @@ function getIdenticonAvatarSvg(entityId: number | string, size: number) { } export const useAutoAvatarImgSrc = (props: AutoAvatarProps) => { - const [base64, setBase64] = useState(undefined as string | undefined); + const [url, setUrl] = useState(undefined as string | undefined); useEffect(() => { let mounted = true; @@ -42,24 +87,17 @@ export const useAutoAvatarImgSrc = (props: AutoAvatarProps) => { props.ownerType === 'PROJECT' ); - svgStringPromise.then((svgString) => { - const base64 = Buffer.from(svgString).toString('base64'); - if (mounted) { - setBase64(base64); - } + svgStringPromise.then((svg) => { + if (mounted) setUrl(svg.toDataUriSync()); }); return () => { mounted = false; }; }, [props.size, props.entityId, props.ownerName, props.ownerType]); - if (!base64) { - return undefined; - } - - return `data:image/svg+xml;base64,${base64}`; + return url; }; function importCreateAvatarFunction() { - return import('@dicebear/avatars').then((m) => m.createAvatar); + return import('@dicebear/core').then((m) => m.createAvatar); } diff --git a/webapp/src/custom.d.ts b/webapp/src/custom.d.ts index 932fe15b5f..7481b7374c 100644 --- a/webapp/src/custom.d.ts +++ b/webapp/src/custom.d.ts @@ -4,6 +4,7 @@ import { Activity, BillingProgress, Cell, + colors, Editor, Emphasis, ExampleBanner, @@ -19,8 +20,6 @@ declare module '*.svg' { const content: React.FunctionComponent>; export default content; } -import { colors } from './colors'; -import { ComponentType, ElementType } from 'react' const all = { ...colors.light, ...colors.dark }; @@ -75,7 +74,8 @@ declare module '@mui/material/Button' { } declare module '@mui/material/ButtonBase' { - interface ButtonBaseOwnProps> extends TProps { + interface ButtonBaseOwnProps> + extends TProps { component?: T; } } diff --git a/webapp/src/store/index.ts b/webapp/src/store/index.ts index 9879b10941..8dd6bedcf1 100644 --- a/webapp/src/store/index.ts +++ b/webapp/src/store/index.ts @@ -1,5 +1,5 @@ import { applyMiddleware, combineReducers, createStore } from 'redux'; -import { composeWithDevTools } from 'redux-devtools-extension'; +import { composeWithDevTools } from '@redux-devtools/extension'; import promise from 'redux-promise-middleware'; import thunkMiddleware from 'redux-thunk'; diff --git a/webapp/src/views/notifications/NotificationsRouter.tsx b/webapp/src/views/notifications/NotificationsRouter.tsx index cb5fa84719..299ad9acb0 100644 --- a/webapp/src/views/notifications/NotificationsRouter.tsx +++ b/webapp/src/views/notifications/NotificationsRouter.tsx @@ -14,15 +14,14 @@ * limitations under the License. */ -import React from 'react' -import { Switch } from 'react-router-dom' -import { DashboardPage } from 'tg.component/layout/DashboardPage' +import React from 'react'; +import { Switch } from 'react-router-dom'; +import { DashboardPage } from 'tg.component/layout/DashboardPage'; export const NotificationsRouter: React.FC = () => { - return ( - - - - - ) -} + return ( + + + + ); +}; From a6e03620c6315120300c16e9f1b2fa736e245f19 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Wed, 14 Feb 2024 09:45:00 +0100 Subject: [PATCH 32/44] feat: skeleton of the notifications view --- webapp/src/component/RootRouter.tsx | 12 ++-- .../layout/TopBar/NotificationBell.tsx | 2 +- webapp/src/constants/links.tsx | 6 ++ webapp/src/custom.d.ts | 4 +- .../notifications/NotificationsRouter.tsx | 56 ++++++++++++++--- .../views/notifications/NotificationsView.tsx | 63 +++++++++++++++++++ 6 files changed, 124 insertions(+), 19 deletions(-) create mode 100644 webapp/src/views/notifications/NotificationsView.tsx diff --git a/webapp/src/component/RootRouter.tsx b/webapp/src/component/RootRouter.tsx index b8f75553eb..74603b822a 100644 --- a/webapp/src/component/RootRouter.tsx +++ b/webapp/src/component/RootRouter.tsx @@ -82,12 +82,12 @@ export const RootRouter = () => ( - - - - - - + + + + + + diff --git a/webapp/src/component/layout/TopBar/NotificationBell.tsx b/webapp/src/component/layout/TopBar/NotificationBell.tsx index 2d4ef63b38..268a444d39 100644 --- a/webapp/src/component/layout/TopBar/NotificationBell.tsx +++ b/webapp/src/component/layout/TopBar/NotificationBell.tsx @@ -48,7 +48,7 @@ export const NotificationBell: React.FC = () => { return ( > extends TProps { + interface ButtonBaseOwnProps> + extends TProps { component?: T; } } diff --git a/webapp/src/views/notifications/NotificationsRouter.tsx b/webapp/src/views/notifications/NotificationsRouter.tsx index cb5fa84719..8ebc63e082 100644 --- a/webapp/src/views/notifications/NotificationsRouter.tsx +++ b/webapp/src/views/notifications/NotificationsRouter.tsx @@ -14,15 +14,51 @@ * limitations under the License. */ -import React from 'react' -import { Switch } from 'react-router-dom' -import { DashboardPage } from 'tg.component/layout/DashboardPage' +import React from 'react'; +import { Switch } from 'react-router-dom'; +import { DashboardPage } from 'tg.component/layout/DashboardPage'; +import { PrivateRoute } from 'tg.component/common/PrivateRoute'; +import { LINKS } from 'tg.constants/links'; +import { NotificationsView } from 'tg.views/notifications/NotificationsView'; +import { useTranslate } from '@tolgee/react'; export const NotificationsRouter: React.FC = () => { - return ( - - - - - ) -} + const { t } = useTranslate(); + + return ( + + + + + + + + + + + + + + + + ); +}; diff --git a/webapp/src/views/notifications/NotificationsView.tsx b/webapp/src/views/notifications/NotificationsView.tsx new file mode 100644 index 0000000000..061f146f47 --- /dev/null +++ b/webapp/src/views/notifications/NotificationsView.tsx @@ -0,0 +1,63 @@ +/** + * Copyright (C) 2024 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { LINKS } from 'tg.constants/links'; + +import { useTranslate } from '@tolgee/react'; +import { BaseSettingsView } from 'tg.component/layout/BaseSettingsView/BaseSettingsView'; +import { NavigationItem } from 'tg.component/navigation/Navigation'; + +type Props = { + unread?: boolean; + read?: boolean; + done?: boolean; + navigation: NavigationItem; +}; + +export const NotificationsView: React.FC = ({ + navigation, + unread, + read, + done, +}) => { + const { t } = useTranslate(); + + return ( + +

test

+
+ ); +}; From f1e0ee9d34d44c4c12691eccea47189fc40e5572 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Mon, 29 Apr 2024 12:13:42 +0200 Subject: [PATCH 33/44] fix: use listagg instead of array_agg Hibernate once again complaining! --- .../src/main/kotlin/io/tolgee/model/Permission.kt | 15 +++++++++------ .../tolgee/model/views/UserProjectMetadataView.kt | 1 + .../NotificationPreferencesService.kt | 4 ++-- .../listeners/ActivityEventListener.kt | 9 +++++++++ .../io/tolgee/repository/PermissionRepository.kt | 7 ++++--- .../io/tolgee/repository/UserAccountRepository.kt | 5 +++-- ....properties => hypersistence-utils.properties} | 0 gradle.properties | 6 +++--- settings.gradle | 2 +- 9 files changed, 32 insertions(+), 17 deletions(-) rename backend/data/src/main/resources/{hibernate-types.properties => hypersistence-utils.properties} (100%) diff --git a/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt b/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt index 4c2a6490eb..7041442e60 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt @@ -200,18 +200,21 @@ class Permission( fetchedStateChangeLanguageIds: Any?, ) { init { - permission.fetchedViewLanguageIds = (fetchedViewLanguageIds as? Array<*>) - ?.mapNotNull { e -> e as? Long } + permission.fetchedViewLanguageIds = (fetchedViewLanguageIds as? String) + ?.split(',') + ?.map { e -> e.toLong() } ?.toSet() ?: emptySet() - permission.fetchedTranslateLanguageIds = (fetchedTranslateLanguageIds as? Array<*>) - ?.mapNotNull { e -> e as? Long } + permission.fetchedTranslateLanguageIds = (fetchedTranslateLanguageIds as? String) + ?.split(',') + ?.map { e -> e.toLong() } ?.toSet() ?: emptySet() - permission.fetchedStateChangeLanguageIds = (fetchedStateChangeLanguageIds as? Array<*>) - ?.mapNotNull { e -> e as? Long } + permission.fetchedStateChangeLanguageIds = (fetchedStateChangeLanguageIds as? String) + ?.split(',') + ?.map { e -> e.toLong() } ?.toSet() ?: emptySet() } diff --git a/backend/data/src/main/kotlin/io/tolgee/model/views/UserProjectMetadataView.kt b/backend/data/src/main/kotlin/io/tolgee/model/views/UserProjectMetadataView.kt index 5ac003fcd9..51b99f231c 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/views/UserProjectMetadataView.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/views/UserProjectMetadataView.kt @@ -35,6 +35,7 @@ class UserProjectMetadataView( val basePermissions = basePermissions?.let { + println(basePermissions) Permission.PermissionWithLanguageIdsWrapper( basePermissions, fetchedBaseViewLanguages, diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt index 43945348d7..031cd92ebf 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt @@ -54,7 +54,7 @@ class NotificationPreferencesService( project: Long, ): NotificationPreferencesDto { // If the user cannot see the project, the project "does not exist". - val scopes = securityService.getProjectPermissionScopes(project, user) ?: emptyArray() + val scopes = securityService.getProjectPermissionScopesNoApiKey(project, user) ?: emptyArray() if (scopes.isEmpty()) throw NotFoundException() val entity = @@ -99,7 +99,7 @@ class NotificationPreferencesService( dto: NotificationPreferencesDto, ): NotificationPreferences { // If the user cannot see the project, the project "does not exist". - val scopes = securityService.getProjectPermissionScopes(project.id, user.id) ?: emptyArray() + val scopes = securityService.getProjectPermissionScopesNoApiKey(project.id, user.id) ?: emptyArray() if (scopes.isEmpty()) throw NotFoundException() return doSetPreferencesOfUser(user, project, dto) diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt index 9e76b91e2b..77e5ce4d0c 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt @@ -124,6 +124,15 @@ class ActivityEventListener( ActivityType.EDIT_PROJECT, ActivityType.NAMESPACE_EDIT, ActivityType.AUTOMATION, + ActivityType.CONTENT_DELIVERY_CONFIG_CREATE, + ActivityType.CONTENT_DELIVERY_CONFIG_UPDATE, + ActivityType.CONTENT_DELIVERY_CONFIG_DELETE, + ActivityType.CONTENT_STORAGE_CREATE, + ActivityType.CONTENT_STORAGE_UPDATE, + ActivityType.CONTENT_STORAGE_DELETE, + ActivityType.WEBHOOK_CONFIG_CREATE, + ActivityType.WEBHOOK_CONFIG_UPDATE, + ActivityType.WEBHOOK_CONFIG_DELETE, null, -> {} } diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/PermissionRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/PermissionRepository.kt index 7657087732..a6cf7d6358 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/PermissionRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/PermissionRepository.kt @@ -12,9 +12,9 @@ interface PermissionRepository : JpaRepository { """ SELECT DISTINCT new io.tolgee.model.Permission${'$'}PermissionWithLanguageIdsWrapper( p, - array_agg(vl.id) OVER (PARTITION BY p.id), - array_agg(tl.id) OVER (PARTITION BY p.id), - array_agg(sl.id) OVER (PARTITION BY p.id) + listagg(str(vl.id), ','), + listagg(str(tl.id), ','), + listagg(str(sl.id), ',') ) FROM Permission p LEFT JOIN p.viewLanguages vl @@ -24,6 +24,7 @@ interface PermissionRepository : JpaRepository { ((:projectId is null and p.project.id is null) or p.project.id = :projectId) and ((:userId is null and p.user.id is null) or p.user.id = :userId) and ((:organizationId is null and p.organization.id is null) or p.organization.id = :organizationId) + GROUP BY p """, ) fun findOneByProjectIdAndUserIdAndOrganizationId( diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt index 8566ea0432..c2af76c5c4 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt @@ -209,9 +209,9 @@ interface UserAccountRepository : JpaRepository { p.id, org_r.type, perm_org, - array_agg(vl_org.id) OVER (PARTITION BY perm_org.id), + listagg(str(vl_org.id), ','), perm, - array_agg(vl.id) OVER (PARTITION BY perm.id), + listagg(str(vl.id), ','), np_global, np_project ) @@ -236,6 +236,7 @@ interface UserAccountRepository : JpaRepository { (perm._scopes IS NOT NULL AND cast(perm._scopes as string) != '{}') OR perm.type IS NOT NULL OR (perm_org._scopes IS NOT NULL AND cast(perm_org._scopes as string) != '{}') OR perm_org.type IS NOT NULL ) + GROUP BY ua.id, p.id, org_r.type, perm_org, perm, np_global, np_project """, ) fun findAllUserProjectMetadataViews(projectId: Long): List diff --git a/backend/data/src/main/resources/hibernate-types.properties b/backend/data/src/main/resources/hypersistence-utils.properties similarity index 100% rename from backend/data/src/main/resources/hibernate-types.properties rename to backend/data/src/main/resources/hypersistence-utils.properties diff --git a/gradle.properties b/gradle.properties index 75119bfea2..b51bc75c3f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,10 +1,10 @@ kotlinVersion=1.9.21 -springBootVersion=3.1.5 +springBootVersion=3.2.5 springDocVersion=2.2.0 jjwtVersion=0.11.2 -hibernateVersion=6.3.1.Final +hibernateVersion=6.5.0.Final amazonAwsSdkVersion=2.20.8 springDependencyManagementVersion=1.0.11.RELEASE -org.gradle.jvmargs=-Xmx6g -Dkotlin.daemon.jvm.options=-Xmx6g +org.gradle.jvmargs=-Xmx2g -Dkotlin.daemon.jvm.options=-Xmx2g org.gradle.parallel=true jacksonVersion=2.13.5 diff --git a/settings.gradle b/settings.gradle index 8fb20c7d75..7ef8cb7d50 100644 --- a/settings.gradle +++ b/settings.gradle @@ -64,7 +64,7 @@ dependencyResolutionManagement { library('liquibaseCore', "org.liquibase:liquibase-core:4.26.0") library('liquibaseHibernate', "org.liquibase.ext:liquibase-hibernate6:4.26.0") library('liquibasePicoli', "info.picocli:picocli:4.6.3") - library('hibernateTypes', "io.hypersistence:hypersistence-utils-hibernate-63:3.7.0") + library('hibernateTypes', "io.hypersistence:hypersistence-utils-hibernate-63:3.7.4") library('redissonSpringBootStarter', "org.redisson:redisson-spring-boot-starter:3.26.0") library('postHog', 'com.posthog.java:posthog:1.1.1') library('micrometerPrometheus', "io.micrometer:micrometer-registry-prometheus:1.9.12") From 0f2dca54ae2d451374097d9900dbce9b6308b6d2 Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Wed, 15 May 2024 14:45:29 +0200 Subject: [PATCH 34/44] fix: Minor updates --- .../repository/notifications/UserNotificationRepository.kt | 4 ---- .../kotlin/io/tolgee/service/security/UserAccountService.kt | 1 - 2 files changed, 5 deletions(-) diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt index dd90944a98..2bab9a6f9d 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt @@ -161,10 +161,6 @@ interface UserNotificationRepository : JpaRepository { notifications: Collection, ) - @Modifying - @Query("DELETE FROM user_notification WHERE marked_done_at < NOW() - INTERVAL '90 DAY'", nativeQuery = true) - fun pruneOldNotifications() // Native query since HQL can't do "INTERVAL" - @Modifying @Query("DELETE FROM UserNotification WHERE recipient.id = :userId") fun deleteAllByUserId(userId: Long) diff --git a/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt b/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt index 88602f9b8d..9dafc352f3 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/security/UserAccountService.kt @@ -343,7 +343,6 @@ class UserAccountService( } fun getAllConnectedUserProjectMetadataViews(projectId: Long): List { - userAccountRepository.findAllUserProjectMetadataViews(projectId).forEach { println(it.userAccountId) } return userAccountRepository.findAllUserProjectMetadataViews(projectId) } From 2c3c8f74cbcd81e2f8881848b43b1a3a8a59e3c8 Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Fri, 17 May 2024 15:28:00 +0200 Subject: [PATCH 35/44] feat: Provide swagger schemas of activity modifications --- .../openApi/OpenApiGroupBuilder.kt | 12 +++ .../activity/ModificationsSchemaGenerator.kt | 98 +++++++++++++++++++ .../activity/RootActivityProviderTest.kt | 46 +++++++++ .../ModificationSchemaGeneratorTest.kt | 12 +++ .../rootActivity/ActivityItemsParser.kt | 78 +++++++++++++++ .../ActivityTreeDefinitionItem.kt | 19 ++++ .../rootActivity/ActivityTreeResultItem.kt | 11 +++ .../rootActivity/ChildItemsProvider.kt | 57 +++++++++++ .../rootActivity/RootActivityProvider.kt | 57 +++++++++++ .../rootActivity/RootItemsProvider.kt | 59 +++++++++++ .../rootActivity/keyRootActivityTree.kt | 23 +++++ .../data/dataImport/ImportTestData.kt | 1 + .../main/kotlin/io/tolgee/model/key/Key.kt | 2 + 13 files changed, 475 insertions(+) create mode 100644 backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/ModificationsSchemaGenerator.kt create mode 100644 backend/app/src/test/kotlin/io/tolgee/activity/RootActivityProviderTest.kt create mode 100644 backend/app/src/test/kotlin/io/tolgee/activity/openApi/ModificationSchemaGeneratorTest.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/ActivityItemsParser.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/ActivityTreeDefinitionItem.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/ActivityTreeResultItem.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/ChildItemsProvider.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/RootActivityProvider.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/RootItemsProvider.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/keyRootActivityTree.kt diff --git a/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/OpenApiGroupBuilder.kt b/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/OpenApiGroupBuilder.kt index 756a7e12b5..1d1116ab26 100644 --- a/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/OpenApiGroupBuilder.kt +++ b/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/OpenApiGroupBuilder.kt @@ -3,6 +3,8 @@ package io.tolgee.configuration.openApi import io.swagger.v3.oas.models.Operation import io.swagger.v3.oas.models.PathItem import io.swagger.v3.oas.models.Paths +import io.tolgee.configuration.openApi.activity.ModificationsSchemaGenerator +import io.tolgee.model.key.Key import io.tolgee.openApiDocs.OpenApiCloudExtension import io.tolgee.openApiDocs.OpenApiEeExtension import io.tolgee.openApiDocs.OpenApiOrderExtension @@ -39,9 +41,19 @@ class OpenApiGroupBuilder( cleanUnusedModels() + addSchmeForTesting() + return@lazy builder.build() } + // todo: Remove this! + private fun addSchmeForTesting() { + val keySchema = ModificationsSchemaGenerator().getModificationSchema(Key::class) + builder.addOpenApiCustomizer { + it.schema("KeyModifiedEntity", keySchema) + } + } + private fun cleanUnusedModels() { builder.addOpenApiCustomizer { OpenApiUnusedSchemaCleaner(it).clean() diff --git a/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/ModificationsSchemaGenerator.kt b/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/ModificationsSchemaGenerator.kt new file mode 100644 index 0000000000..72b6608758 --- /dev/null +++ b/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/ModificationsSchemaGenerator.kt @@ -0,0 +1,98 @@ +package io.tolgee.configuration.openApi.activity + +import io.swagger.v3.core.converter.AnnotatedType +import io.swagger.v3.core.converter.ModelConverters +import io.swagger.v3.oas.models.media.Schema +import io.tolgee.activity.annotation.ActivityDescribingProp +import io.tolgee.activity.annotation.ActivityLoggedProp +import io.tolgee.activity.data.EntityDescription +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 +import kotlin.reflect.full.findAnnotation +import kotlin.reflect.full.memberProperties + +class ModificationsSchemaGenerator { + fun getModificationSchema(entityClass: KClass<*>): Schema<*> { + val schema = getEntitySchema(entityClass) + val loggedProps = getAllLoggedProps(entityClass) + val simplePropNames = loggedProps.getSimpleProps().map { it.name } + val schemaSimpleProps = schema.properties.filterKeys { it in simplePropNames } + + val singlePropChangeMap = + schemaSimpleProps.map { (name, prop) -> + name to prop.toChangeSchema() + }.toMap() + + val complexProps = loggedProps.getComplexProps() + val complexPropChangeMap = + complexProps.map { + it.name to getModificationSchemaForComplexProp(it.returnType.classifier as KClass<*>) + }.toMap() + + schema.properties = singlePropChangeMap + complexPropChangeMap + + return schema + } + + private fun getModificationSchemaForComplexProp(it: KClass<*>): Schema<*> { + val describingProps = it.getDescriptionProps().map { it.name } + val entitySchema = getEntitySchema(it) + val schemaDescribingProps = + entitySchema.properties.filterKeys { propertyName -> propertyName in describingProps } + descriptionSchema.properties["data"]?.properties = schemaDescribingProps + descriptionSchema.additionalProperties = null + return descriptionSchema.toChangeSchema() + } + + private fun Schema<*>.toChangeSchema(): Schema<*> { + val changeSchema = Schema() + changeSchema.addProperty("old", this) + changeSchema.addProperty("new", this) + changeSchema.nullable = true + return changeSchema + } + + private fun getEntitySchema(entityClass: KClass<*>): Schema<*> = + ModelConverters.getInstance() + .readAllAsResolvedSchema(AnnotatedType(entityClass.java)) + .schema + + private fun getAllLoggedProps(entityClass: KClass<*>): List> { + return entityClass.memberProperties + .filter { it.findAnnotation() != null } + .map { it } + } + + private fun KClass<*>.getDescriptionProps(): List> { + return memberProperties + .filter { it.findAnnotation() != null } + .map { it }.filter { it.returnType.classifier in simpleTypes } + } + + private fun List>.getSimpleProps(): List> { + return this + .filter { prop -> + simpleTypes.any { it == prop.returnType.classifier } + } + } + + private fun List>.getComplexProps(): List> { + return this + .filter { prop -> + simpleTypes.none { it == prop.returnType.classifier } + } + } + + val descriptionSchema by lazy { + getEntitySchema(EntityDescription::class) + } + + companion object { + val simpleTypes = + setOf( + Int::class, Long::class, Double::class, Float::class, + Boolean::class, Char::class, Byte::class, Short::class, + String::class, Enum::class, + ) + } +} diff --git a/backend/app/src/test/kotlin/io/tolgee/activity/RootActivityProviderTest.kt b/backend/app/src/test/kotlin/io/tolgee/activity/RootActivityProviderTest.kt new file mode 100644 index 0000000000..26d3e5a61b --- /dev/null +++ b/backend/app/src/test/kotlin/io/tolgee/activity/RootActivityProviderTest.kt @@ -0,0 +1,46 @@ +package io.tolgee.activity + +import io.tolgee.ProjectAuthControllerTest +import io.tolgee.activity.rootActivity.KeyActivityTreeDefinitionItem +import io.tolgee.activity.rootActivity.RootActivityProvider +import io.tolgee.development.testDataBuilder.data.dataImport.ImportTestData +import io.tolgee.fixtures.andIsOk +import org.junit.jupiter.api.Test +import org.springframework.data.domain.Pageable + +class RootActivityProviderTest : ProjectAuthControllerTest("/v2/projects/") { + @Test + fun `it applies the import`() { + importData() + val latestRevisionId = getLatestRevisionId() + val items = + RootActivityProvider( + applicationContext, + latestRevisionId!!, + KeyActivityTreeDefinitionItem, + Pageable.ofSize(100), + ).provide() + items + } + + private fun getLatestRevisionId(): Long? { + return entityManager.createQuery( + "select max(r.id) from ActivityRevision r", + Long::class.java, + ).singleResult + } + + private fun importData() { + val testData = ImportTestData() + testData.addFilesWithNamespaces().importFrenchInNs.existingLanguage = testData.french + testData.addKeyMetadata() + testData.setAllResolved() + testData.setAllOverride() + testDataService.saveTestData(testData.root) + val user = testData.root.data.userAccounts[0].self + val projectId = testData.project.id + loginAsUser(user.username) + val path = "/v2/projects/$projectId/import/apply" + performAuthPut(path, null).andIsOk + } +} diff --git a/backend/app/src/test/kotlin/io/tolgee/activity/openApi/ModificationSchemaGeneratorTest.kt b/backend/app/src/test/kotlin/io/tolgee/activity/openApi/ModificationSchemaGeneratorTest.kt new file mode 100644 index 0000000000..75f67b1e2f --- /dev/null +++ b/backend/app/src/test/kotlin/io/tolgee/activity/openApi/ModificationSchemaGeneratorTest.kt @@ -0,0 +1,12 @@ +package io.tolgee.activity.openApi + +import io.tolgee.configuration.openApi.activity.ModificationsSchemaGenerator +import io.tolgee.model.key.Key +import org.junit.jupiter.api.Test + +class ModificationSchemaGeneratorTest { + @Test + fun `generates for key`() { + val schema = ModificationsSchemaGenerator().getModificationSchema(Key::class) + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/ActivityItemsParser.kt b/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/ActivityItemsParser.kt new file mode 100644 index 0000000000..8c2fe40a76 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/ActivityItemsParser.kt @@ -0,0 +1,78 @@ +package io.tolgee.activity.rootActivity + +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue +import org.springframework.stereotype.Component + +@Component +class ActivityItemsParser( + private val objectMapper: ObjectMapper, +) { + fun parse(items: List>): List { + return items.map { + parseItem(it) + } + } + + private fun parseItem(item: Array): ActivityTreeResultItem { + val modifications = item[2].parseJsonOrNull() + val type = Type.getByValue(item[4] as String) + return ActivityTreeResultItem( + entityClass = item[0] as String, + description = getDescription(modifications, item), + modifications = modifications, + entityId = item[3] as Long, + type = type, + parentId = getParentId(item), + ) + } + + private fun getParentId(item: Array): Long? { + return try { + item[5] as? Long + } catch (e: IndexOutOfBoundsException) { + null + } + } + + private fun getDescription( + modifications: Map?, + item: Array, + ): Map { + val description = item[1].parseJsonOrNull()?.toMutableMap() ?: mutableMapOf() + + val new = getNewFromModifications(modifications) ?: return description + + return description + new + } + + private fun getNewFromModifications(modifications: Map?): Map? { + return modifications?.map { + @Suppress("UNCHECKED_CAST") + it.key to ((it.value as? Map)?.get("new")) + }?.toMap() + } + + private fun Any?.parseJsonOrNull(): Map? { + if (this is String) { + return try { + objectMapper.readValue>(this) + } catch (e: Exception) { + null + } + } + return null + } + + enum class Type(val value: String) { + MODIFIED_ENTITY("AME"), + DESCRIBING_ENTITY("ADE"), + ; + + companion object { + fun getByValue(value: String): Type { + return entries.first { it.value == value } + } + } + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/ActivityTreeDefinitionItem.kt b/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/ActivityTreeDefinitionItem.kt new file mode 100644 index 0000000000..5f57c7f977 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/ActivityTreeDefinitionItem.kt @@ -0,0 +1,19 @@ +package io.tolgee.activity.rootActivity + +import io.tolgee.model.EntityWithId +import kotlin.reflect.KClass + +/** + * In some cases we need to return the data in activities in structured way by some root entity, for example for import + * we need to return the data rooted by key, so we can list the data on front-end nicely. + */ +class ActivityTreeDefinitionItem( + val entityClass: KClass, + /** + * The field of the child entity that describes the parent entity. + * E.g., For `Translation` entity this would be the `key` + */ + val describingField: String? = null, + val single: Boolean = false, + val children: Map = emptyMap(), +) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/ActivityTreeResultItem.kt b/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/ActivityTreeResultItem.kt new file mode 100644 index 0000000000..8b8da352a4 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/ActivityTreeResultItem.kt @@ -0,0 +1,11 @@ +package io.tolgee.activity.rootActivity + +data class ActivityTreeResultItem( + val entityClass: String, + val description: Map?, + val modifications: Map?, + val entityId: Long, + val type: ActivityItemsParser.Type, + val parentId: Long?, + var children: MutableMap? = null, +) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/ChildItemsProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/ChildItemsProvider.kt new file mode 100644 index 0000000000..e194c5c519 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/ChildItemsProvider.kt @@ -0,0 +1,57 @@ +package io.tolgee.activity.rootActivity + +import jakarta.persistence.EntityManager +import org.springframework.context.ApplicationContext + +class ChildItemsProvider( + private val activityRevisionId: Long, + private val treeItem: ActivityTreeDefinitionItem, + private val applicationContext: ApplicationContext, + private val parentIds: List, +) { + fun provide(): List { + val rootItems = getRootItemsRaw() + return itemsParser.parse(rootItems) + } + + private fun getRootItemsRaw(): List> { + return entityManager.createNativeQuery( + """ + select entity_class, ame.describing_data, modifications, ame.entity_id id, 'AME' as type, + (ame.describing_relations -> :describingField -> 'entityId')::bigint as parent_id + from activity_modified_entity ame + where ame.entity_class = :entityClass + and ame.activity_revision_id = :revisionId + and (ame.describing_relations -> :describingField -> 'entityId')::bigint in :ids + union + select ade.entity_class, ade.data, null, ade.entity_id id, 'ADE' as type, + (ade.describing_relations -> :describingField -> 'entityId')::bigint as parent_id + from activity_describing_entity ade + where ade.activity_revision_id = :revisionId + and ade.entity_class = :entityClass + and (ade.describing_relations -> :describingField -> 'entityId')::bigint in :ids + and ade.entity_id not in (select ame.entity_id id + from activity_modified_entity ame + where ame.activity_revision_id = :revisionId + and ame.entity_class = :entityClass + and (ame.describing_relations -> :describingField -> 'entityId')::bigint in :ids + ) + order by id + """, + Array::class.java, + ) + .setParameter("entityClass", treeItem.entityClass.simpleName) + .setParameter("describingField", treeItem.describingField) + .setParameter("revisionId", activityRevisionId) + .setParameter("ids", parentIds) + .resultList as List> + } + + val entityManager: EntityManager by lazy { + applicationContext.getBean(EntityManager::class.java) + } + + val itemsParser: ActivityItemsParser by lazy { + applicationContext.getBean(ActivityItemsParser::class.java) + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/RootActivityProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/RootActivityProvider.kt new file mode 100644 index 0000000000..d58bcae9b7 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/RootActivityProvider.kt @@ -0,0 +1,57 @@ +package io.tolgee.activity.rootActivity + +import jakarta.persistence.EntityManager +import org.springframework.context.ApplicationContext +import org.springframework.data.domain.Pageable + +class RootActivityProvider( + private val applicationContext: ApplicationContext, + private val activityRevisionId: Long, + private val activityTreeDefinitionItem: ActivityTreeDefinitionItem, + private val pageable: Pageable, +) { + private val rootItems by lazy { + RootItemsProvider( + pageable, + activityRevisionId, + activityTreeDefinitionItem.entityClass, + applicationContext, + ).provide() + } + + fun provide(): List { + addChildren(activityTreeDefinitionItem, rootItems) + return rootItems + } + + private fun addChildren( + parentItemDefinition: ActivityTreeDefinitionItem, + parentItems: List, + ) { + val parentIds = parentItems.map { it.entityId } + parentItemDefinition.children.map { (key, item) -> + val childItems = + ChildItemsProvider(activityRevisionId, item, applicationContext, parentIds).provide().groupBy { it.parentId } + + childItems.forEach { + addChildren(item, it.value) + } + + rootItems.forEach { parentItem -> + val children = + parentItem.children ?: let { + parentItem.children = mutableMapOf() + parentItem.children!! + } + + childItems[parentItem.entityId]?.let { + children[key] = if (item.single) it.singleOrNull() else it + } + } + } + } + + val entityManager: EntityManager by lazy { + applicationContext.getBean(EntityManager::class.java) + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/RootItemsProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/RootItemsProvider.kt new file mode 100644 index 0000000000..0920a735b5 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/RootItemsProvider.kt @@ -0,0 +1,59 @@ +package io.tolgee.activity.rootActivity + +import io.tolgee.model.EntityWithId +import jakarta.persistence.EntityManager +import org.springframework.context.ApplicationContext +import org.springframework.data.domain.Pageable +import kotlin.reflect.KClass + +class RootItemsProvider( + private val pageable: Pageable, + private val activityRevisionId: Long, + private val rootEntityClass: KClass, + private val applicationContext: ApplicationContext, +) { + fun provide(): List { + val rootItems = getRootItemsRaw() + return itemsParser.parse(rootItems) + } + + private fun getRootItemsRaw(): List> { + val limit = pageable.pageSize + val offset = pageable.offset + return entityManager.createNativeQuery( + """ + select entity_class, ame.describing_data, modifications, ame.entity_id id, 'AME' as type + from activity_modified_entity ame + where ame.entity_class = :entityClass + and ame.activity_revision_id = :revisionId + union + select ade.entity_class, ade.data, null, ade.entity_id id, 'ADE' as type + from activity_describing_entity ade + where ade.activity_revision_id = :revisionId + and ade.entity_class = :entityClass and ade.entity_id not in ( + select ame.entity_id id + from activity_modified_entity ame + where ame.activity_revision_id = :revisionId + and ame.entity_class = :entityClass + ) + order by id + limit :limit + offset :offset + """, + Array::class.java, + ) + .setParameter("entityClass", rootEntityClass.simpleName) + .setParameter("revisionId", activityRevisionId) + .setParameter("limit", limit) + .setParameter("offset", offset) + .resultList as List> + } + + val entityManager: EntityManager by lazy { + applicationContext.getBean(EntityManager::class.java) + } + + val itemsParser: ActivityItemsParser by lazy { + applicationContext.getBean(ActivityItemsParser::class.java) + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/keyRootActivityTree.kt b/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/keyRootActivityTree.kt new file mode 100644 index 0000000000..4793568487 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/keyRootActivityTree.kt @@ -0,0 +1,23 @@ +package io.tolgee.activity.rootActivity + +import io.tolgee.model.key.Key +import io.tolgee.model.key.KeyMeta +import io.tolgee.model.translation.Translation + +val KeyActivityTreeDefinitionItem = + ActivityTreeDefinitionItem( + entityClass = Key::class, + children = + mapOf( + "translations" to + ActivityTreeDefinitionItem( + describingField = "key", + entityClass = Translation::class, + ), + "keyMeta" to + ActivityTreeDefinitionItem( + describingField = "key", + entityClass = KeyMeta::class, + ), + ), + ) diff --git a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/dataImport/ImportTestData.kt b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/dataImport/ImportTestData.kt index d448c70c5b..a204b39c64 100644 --- a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/dataImport/ImportTestData.kt +++ b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/dataImport/ImportTestData.kt @@ -343,6 +343,7 @@ class ImportTestData { line = 10 fromImport = true } + description = "This is a key" } projectBuilder.data.imports[0].data.importFiles[0].data.importKeys[2].addMeta { diff --git a/backend/data/src/main/kotlin/io/tolgee/model/key/Key.kt b/backend/data/src/main/kotlin/io/tolgee/model/key/Key.kt index fd2236b77d..7eeb3ace0b 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/key/Key.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/key/Key.kt @@ -1,5 +1,6 @@ package io.tolgee.model.key +import com.fasterxml.jackson.annotation.JsonIgnore import io.tolgee.activity.annotation.ActivityDescribingProp import io.tolgee.activity.annotation.ActivityEntityDescribingPaths import io.tolgee.activity.annotation.ActivityLoggedEntity @@ -78,6 +79,7 @@ class Key( this.translations = translations } + @get:JsonIgnore val path: PathDTO get() = PathDTO.fromFullPath(name) From c6ed341c05f675632dd062a0ed19782a2f9718a9 Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Thu, 30 May 2024 13:52:21 +0200 Subject: [PATCH 36/44] feat: Activity type definitions, activity grouping --- backend/app/build.gradle | 1 + .../openApi/OpenApiGroupBuilder.kt | 12 +- .../activity/ModificationsSchemaGenerator.kt | 64 +- .../activity/ProjectActivityModelEnhancer.kt | 101 + backend/data/build.gradle | 2 +- .../io/tolgee/activity/data/ActivityType.kt | 58 +- .../data/EntityModificationTypeDefinition.kt | 13 + .../activity/groups/ActivityGroupType.kt | 468 ++ .../GroupEntityModificationDefinition.kt | 12 + .../io/tolgee/dtos/request/key/EditKeyDto.kt | 2 +- .../io/tolgee/model/activity/ActivityGroup.kt | 119 + file | 0 settings.gradle | 1 + webapp/src/service/apiSchema.generated.ts | 6243 +++++++++++++++-- 14 files changed, 6617 insertions(+), 479 deletions(-) create mode 100644 backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/ProjectActivityModelEnhancer.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/data/EntityModificationTypeDefinition.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupType.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/GroupEntityModificationDefinition.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityGroup.kt delete mode 100644 file diff --git a/backend/app/build.gradle b/backend/app/build.gradle index 1575e7cafc..04733bba5c 100644 --- a/backend/app/build.gradle +++ b/backend/app/build.gradle @@ -106,6 +106,7 @@ dependencies { * MISC */ implementation libs.commonsCodec + implementation libs.commonsText implementation libs.amazonS3 implementation libs.amazonSTS implementation libs.icu4j diff --git a/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/OpenApiGroupBuilder.kt b/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/OpenApiGroupBuilder.kt index 1d1116ab26..f4d8c9cc92 100644 --- a/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/OpenApiGroupBuilder.kt +++ b/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/OpenApiGroupBuilder.kt @@ -3,8 +3,7 @@ package io.tolgee.configuration.openApi import io.swagger.v3.oas.models.Operation import io.swagger.v3.oas.models.PathItem import io.swagger.v3.oas.models.Paths -import io.tolgee.configuration.openApi.activity.ModificationsSchemaGenerator -import io.tolgee.model.key.Key +import io.tolgee.configuration.openApi.activity.ProjectActivityModelEnhancer import io.tolgee.openApiDocs.OpenApiCloudExtension import io.tolgee.openApiDocs.OpenApiEeExtension import io.tolgee.openApiDocs.OpenApiOrderExtension @@ -41,16 +40,17 @@ class OpenApiGroupBuilder( cleanUnusedModels() - addSchmeForTesting() + updateActivitySchema() return@lazy builder.build() } // todo: Remove this! - private fun addSchmeForTesting() { - val keySchema = ModificationsSchemaGenerator().getModificationSchema(Key::class) + private fun updateActivitySchema() { +// val keySchema = ModificationsSchemaGenerator().getModificationSchema(Key::class) builder.addOpenApiCustomizer { - it.schema("KeyModifiedEntity", keySchema) + ProjectActivityModelEnhancer(it).enhance() +// it.schema("KeyModifiedEntity", keySchema) } } diff --git a/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/ModificationsSchemaGenerator.kt b/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/ModificationsSchemaGenerator.kt index 72b6608758..718c5748eb 100644 --- a/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/ModificationsSchemaGenerator.kt +++ b/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/ModificationsSchemaGenerator.kt @@ -6,14 +6,48 @@ import io.swagger.v3.oas.models.media.Schema import io.tolgee.activity.annotation.ActivityDescribingProp import io.tolgee.activity.annotation.ActivityLoggedProp import io.tolgee.activity.data.EntityDescription +import io.tolgee.activity.data.EntityModificationTypeDefinition import kotlin.reflect.KClass +import kotlin.reflect.KClassifier import kotlin.reflect.KProperty1 import kotlin.reflect.full.findAnnotation +import kotlin.reflect.full.isSubclassOf import kotlin.reflect.full.memberProperties class ModificationsSchemaGenerator { - fun getModificationSchema(entityClass: KClass<*>): Schema<*> { + fun getModificationSchema( + entityClass: KClass<*>, + definition: EntityModificationTypeDefinition<*>, + ): Schema<*> { val schema = getEntitySchema(entityClass) + schema.required = emptyList() + val properties = getProperties(entityClass, schema) + + if (definition.isOnlyCreation()) { + properties.forEach { (_, prop) -> + prop.properties["old"] = createNullSchema() + } + } + + schema.properties = properties + + return schema + } + + private fun createNullSchema(): Schema { + val schema = Schema() + schema.type = "null" + return schema + } + + private fun EntityModificationTypeDefinition<*>.isOnlyCreation(): Boolean { + return creation && !deletion && modificationProps.isNullOrEmpty() + } + + private fun getProperties( + entityClass: KClass<*>, + schema: Schema<*>, + ): Map> { val loggedProps = getAllLoggedProps(entityClass) val simplePropNames = loggedProps.getSimpleProps().map { it.name } val schemaSimpleProps = schema.properties.filterKeys { it in simplePropNames } @@ -29,17 +63,18 @@ class ModificationsSchemaGenerator { it.name to getModificationSchemaForComplexProp(it.returnType.classifier as KClass<*>) }.toMap() - schema.properties = singlePropChangeMap + complexPropChangeMap - - return schema + return singlePropChangeMap + complexPropChangeMap } private fun getModificationSchemaForComplexProp(it: KClass<*>): Schema<*> { val describingProps = it.getDescriptionProps().map { it.name } val entitySchema = getEntitySchema(it) val schemaDescribingProps = - entitySchema.properties.filterKeys { propertyName -> propertyName in describingProps } - descriptionSchema.properties["data"]?.properties = schemaDescribingProps + entitySchema.properties?.filterKeys { propertyName -> propertyName in describingProps } + descriptionSchema.properties["data"]?.let { dataProp -> + dataProp.properties = schemaDescribingProps + dataProp.additionalProperties = null + } descriptionSchema.additionalProperties = null return descriptionSchema.toChangeSchema() } @@ -48,14 +83,13 @@ class ModificationsSchemaGenerator { val changeSchema = Schema() changeSchema.addProperty("old", this) changeSchema.addProperty("new", this) - changeSchema.nullable = true return changeSchema } private fun getEntitySchema(entityClass: KClass<*>): Schema<*> = ModelConverters.getInstance() .readAllAsResolvedSchema(AnnotatedType(entityClass.java)) - .schema + .schema ?: Schema() private fun getAllLoggedProps(entityClass: KClass<*>): List> { return entityClass.memberProperties @@ -66,33 +100,37 @@ class ModificationsSchemaGenerator { private fun KClass<*>.getDescriptionProps(): List> { return memberProperties .filter { it.findAnnotation() != null } - .map { it }.filter { it.returnType.classifier in simpleTypes } + .map { it }.filter { it.returnType.classifier.isSimpleType() } } private fun List>.getSimpleProps(): List> { return this .filter { prop -> - simpleTypes.any { it == prop.returnType.classifier } + prop.returnType.classifier.isSimpleType() } } private fun List>.getComplexProps(): List> { return this .filter { prop -> - simpleTypes.none { it == prop.returnType.classifier } + !prop.returnType.classifier.isSimpleType() } } - val descriptionSchema by lazy { + private val descriptionSchema by lazy { getEntitySchema(EntityDescription::class) } + private fun KClassifier?.isSimpleType(): Boolean { + return simpleTypes.any { (this as? KClass<*>)?.isSubclassOf(it) == true } + } + companion object { val simpleTypes = setOf( Int::class, Long::class, Double::class, Float::class, Boolean::class, Char::class, Byte::class, Short::class, - String::class, Enum::class, + String::class, Enum::class, Map::class, ) } } diff --git a/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/ProjectActivityModelEnhancer.kt b/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/ProjectActivityModelEnhancer.kt new file mode 100644 index 0000000000..b256290fa5 --- /dev/null +++ b/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/ProjectActivityModelEnhancer.kt @@ -0,0 +1,101 @@ +package io.tolgee.configuration.openApi.activity + +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import io.swagger.v3.oas.models.OpenAPI +import io.swagger.v3.oas.models.media.Schema +import io.tolgee.activity.data.ActivityType +import org.apache.commons.text.CaseUtils +import kotlin.reflect.KClass + +class ProjectActivityModelEnhancer( + private val openApi: OpenAPI, +) { + private val baseSchema = + openApi.components.schemas["ProjectActivityModel"] + ?: throw IllegalStateException("ProjectActivityModel schema not found") + + private val modifiedEntityModel = + openApi.components.schemas["ModifiedEntityModel"] + ?: throw IllegalStateException("ModifiedEntityModel schema not found") + + private val baseRequired = baseSchema.required + + private val baseProperties = baseSchema.properties + + private val baseType = baseSchema.type + + fun enhance() { + baseSchema.required = null + baseSchema.properties = null + baseSchema.type = null + + baseSchema.oneOf = generateSchemas() + } + + private fun generateSchemas(): MutableList>? { + return ActivityType.entries.map { + val schemaName = it.getSchemaName() + Schema().apply { + name = schemaName + properties = getPropertiesForActivitySchema(it) + type = baseType + required = baseRequired + } + }.toMutableList().also { schemas -> + openApi.components.schemas.putAll(schemas.associateBy { it.name }) + } + } + + private fun getPropertiesForActivitySchema(activityType: ActivityType): MutableMap> { + val newProperties = baseProperties.toMutableMap() + newProperties["type"] = getNewTypeProperty(newProperties, activityType) + newProperties["modifiedEntities"] = getNewModifiedEntitiesProperty(activityType) + return newProperties + } + + private fun getNewModifiedEntitiesProperty(activityType: ActivityType): Schema { + val properties = + activityType.typeDefinitions?.map { (entityClass, definition) -> + val schema = activityType.createModifiedEntityModel(entityClass) + schema.properties["modifications"] = ModificationsSchemaGenerator().getModificationSchema(entityClass, definition) + entityClass.simpleName to schema + }?.toMap() + + return Schema().apply { + name = activityType.getModifiedEntitiesSchemaName() + this.properties = properties + } + } + + private fun getNewTypeProperty( + properties: Map?>, + activityType: ActivityType, + ): Schema<*> { + val oldTypeProperty = properties["type"] ?: throw IllegalStateException("Type property not found") + val newType = oldTypeProperty.clone() + @Suppress("TYPE_MISMATCH_WARNING") + newType.enum = newType.enum.filter { it == activityType.name } + return newType + } + + fun Schema<*>.clone(): Schema<*> { + val objectMapper = jacksonObjectMapper() + return objectMapper.readValue(objectMapper.writeValueAsString(this), Schema::class.java) + } + + fun ActivityType.createModifiedEntityModel(entityClass: KClass<*>): Schema<*> { + return Schema().apply { + name = this@createModifiedEntityModel.getModifiedEntitySchemaName(entityClass) + properties = modifiedEntityModel.properties.toMutableMap() + } + } + + private fun ActivityType.getModifiedEntitySchemaName(entityClass: KClass<*>): String { + return "ModifiedEntity" + CaseUtils.toCamelCase(this.name, true, '_') + entityClass.simpleName + "Model" + } + + private fun ActivityType.getSchemaName() = "ProjectActivity" + CaseUtils.toCamelCase(this.name, true, '_') + "Model" + + private fun ActivityType.getModifiedEntitiesSchemaName() = + "ModifiedEntities" + CaseUtils.toCamelCase(this.name, true, '_') + "Model" +} diff --git a/backend/data/build.gradle b/backend/data/build.gradle index d447351bcc..ee98b04a36 100644 --- a/backend/data/build.gradle +++ b/backend/data/build.gradle @@ -150,7 +150,7 @@ dependencies { * MISC */ implementation libs.commonsCodec - implementation group: 'org.apache.commons', name: 'commons-text', version: '1.10.0' + implementation libs.commonsText implementation libs.icu4j implementation libs.jjwtApi implementation libs.jjwtImpl diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/data/ActivityType.kt b/backend/data/src/main/kotlin/io/tolgee/activity/data/ActivityType.kt index 7a5a816f70..d2280a6f01 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/data/ActivityType.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/data/ActivityType.kt @@ -4,6 +4,9 @@ import io.tolgee.activity.PublicParamsProvider import io.tolgee.batch.BatchActivityParamsProvider import io.tolgee.model.EntityWithId import io.tolgee.model.Language +import io.tolgee.model.key.Key +import io.tolgee.model.key.KeyMeta +import io.tolgee.model.translation.Translation import kotlin.reflect.KClass enum class ActivityType( @@ -16,11 +19,42 @@ enum class ActivityType( * not contain any changes in fields market for activity logging */ val saveWithoutModification: Boolean = false, + val typeDefinitions: Map, EntityModificationTypeDefinition<*>>? = null, ) { UNKNOWN, - SET_TRANSLATION_STATE, - SET_TRANSLATIONS, - DISMISS_AUTO_TRANSLATED_STATE, + SET_TRANSLATION_STATE( + typeDefinitions = + mapOf( + Translation::class to + EntityModificationTypeDefinition( + creation = false, + modificationProps = arrayOf(Translation::state, Translation::outdated, Translation::mtProvider), + deletion = false, + ), + ), + ), + SET_TRANSLATIONS( + typeDefinitions = + mapOf( + Translation::class to + EntityModificationTypeDefinition( + creation = true, + modificationProps = arrayOf(), + deletion = true, + ), + ), + ), + DISMISS_AUTO_TRANSLATED_STATE( + typeDefinitions = + mapOf( + Translation::class to + EntityModificationTypeDefinition( + creation = false, + modificationProps = arrayOf(Translation::outdated, Translation::mtProvider), + deletion = false, + ), + ), + ), SET_OUTDATED_FLAG, TRANSLATION_COMMENT_ADD, TRANSLATION_COMMENT_DELETE, @@ -31,7 +65,23 @@ enum class ActivityType( KEY_TAGS_EDIT, KEY_NAME_EDIT, KEY_DELETE(true), - CREATE_KEY, + CREATE_KEY( + typeDefinitions = + mapOf( + Key::class to + EntityModificationTypeDefinition( + creation = true, + modificationProps = null, + deletion = false, + ), + KeyMeta::class to + EntityModificationTypeDefinition( + creation = true, + modificationProps = null, + deletion = false, + ), + ), + ), COMPLEX_EDIT, IMPORT(true), CREATE_LANGUAGE, diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/data/EntityModificationTypeDefinition.kt b/backend/data/src/main/kotlin/io/tolgee/activity/data/EntityModificationTypeDefinition.kt new file mode 100644 index 0000000000..33f59356bb --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/data/EntityModificationTypeDefinition.kt @@ -0,0 +1,13 @@ +package io.tolgee.activity.data + +import io.tolgee.model.EntityWithId +import kotlin.reflect.KProperty1 + +class EntityModificationTypeDefinition( + val creation: Boolean = false, + /** + * If null then all props can be modified + */ + val modificationProps: Array>? = emptyArray(), + val deletion: Boolean = false, +) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupType.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupType.kt new file mode 100644 index 0000000000..69843f2306 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupType.kt @@ -0,0 +1,468 @@ +package io.tolgee.activity.groups + +import io.tolgee.activity.data.ActivityType +import io.tolgee.activity.data.RevisionType +import io.tolgee.model.Language +import io.tolgee.model.Project +import io.tolgee.model.Screenshot +import io.tolgee.model.contentDelivery.ContentDeliveryConfig +import io.tolgee.model.contentDelivery.ContentStorage +import io.tolgee.model.enums.TranslationState +import io.tolgee.model.key.Key +import io.tolgee.model.key.KeyMeta +import io.tolgee.model.key.Namespace +import io.tolgee.model.key.Tag +import io.tolgee.model.key.screenshotReference.KeyScreenshotReference +import io.tolgee.model.translation.Translation +import io.tolgee.model.translation.TranslationComment +import io.tolgee.model.webhook.WebhookConfig + +enum class ActivityGroupType( + val sourceActivityTypes: List, + val allowedGroupEntityModificationDefinitions: List>, +) { + SET_TRANSLATION_STATE( + listOf(ActivityType.SET_TRANSLATION_STATE, ActivityType.COMPLEX_EDIT), + listOf( + GroupEntityModificationDefinition( + entityClass = Translation::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(Translation::state, Translation::outdated, Translation::mtProvider), + ), + ), + ), + + REVIEW( + listOf(ActivityType.SET_TRANSLATION_STATE, ActivityType.COMPLEX_EDIT), + listOf( + GroupEntityModificationDefinition( + entityClass = Translation::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(Translation::state, Translation::outdated, Translation::mtProvider), + allowedValues = mapOf(Translation::state to TranslationState.REVIEWED), + ), + ), + ), + + SET_TRANSLATIONS( + listOf(ActivityType.SET_TRANSLATIONS, ActivityType.COMPLEX_EDIT), + listOf( + GroupEntityModificationDefinition( + entityClass = Translation::class, + revisionTypes = listOf(RevisionType.ADD, RevisionType.DEL, RevisionType.MOD), + ), + ), + ), + + DISMISS_AUTO_TRANSLATED_STATE( + listOf(ActivityType.DISMISS_AUTO_TRANSLATED_STATE), + listOf( + GroupEntityModificationDefinition( + entityClass = Translation::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(Translation::auto, Translation::mtProvider), + allowedValues = mapOf(Translation::mtProvider to null, Translation::auto to false), + ), + ), + ), + + SET_OUTDATED_FLAG( + listOf(ActivityType.SET_OUTDATED_FLAG), + listOf( + GroupEntityModificationDefinition( + entityClass = Translation::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(Translation::outdated), + ), + ), + ), + + TRANSLATION_COMMENT_ADD( + listOf(ActivityType.TRANSLATION_COMMENT_ADD), + listOf( + GroupEntityModificationDefinition( + entityClass = TranslationComment::class, + revisionTypes = listOf(RevisionType.ADD), + ), + GroupEntityModificationDefinition( + entityClass = Translation::class, + revisionTypes = listOf(RevisionType.ADD), + ), + ), + ), + + TRANSLATION_COMMENT_DELETE( + listOf(ActivityType.TRANSLATION_COMMENT_DELETE), + listOf( + GroupEntityModificationDefinition( + entityClass = TranslationComment::class, + revisionTypes = listOf(RevisionType.DEL), + ), + ), + ), + + TRANSLATION_COMMENT_EDIT( + listOf(ActivityType.TRANSLATION_COMMENT_EDIT), + listOf( + GroupEntityModificationDefinition( + entityClass = TranslationComment::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(TranslationComment::text), + ), + ), + ), + + TRANSLATION_COMMENT_SET_STATE( + listOf(ActivityType.TRANSLATION_COMMENT_SET_STATE), + listOf( + GroupEntityModificationDefinition( + entityClass = TranslationComment::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(TranslationComment::state), + ), + ), + ), + + SCREENSHOT_DELETE( + listOf(ActivityType.SCREENSHOT_DELETE, ActivityType.COMPLEX_EDIT), + listOf( + GroupEntityModificationDefinition( + entityClass = Screenshot::class, + revisionTypes = listOf(RevisionType.DEL), + ), + GroupEntityModificationDefinition( + entityClass = KeyScreenshotReference::class, + revisionTypes = listOf(RevisionType.DEL), + ), + ), + ), + + SCREENSHOT_ADD( + listOf(ActivityType.SCREENSHOT_ADD, ActivityType.COMPLEX_EDIT), + listOf( + GroupEntityModificationDefinition( + entityClass = Screenshot::class, + revisionTypes = listOf(RevisionType.ADD), + ), + GroupEntityModificationDefinition( + entityClass = KeyScreenshotReference::class, + revisionTypes = listOf(RevisionType.ADD), + ), + ), + ), + + KEY_TAGS_EDIT( + listOf( + ActivityType.KEY_TAGS_EDIT, + ActivityType.COMPLEX_EDIT, + ActivityType.BATCH_TAG_KEYS, + ActivityType.BATCH_UNTAG_KEYS, + ), + listOf( + GroupEntityModificationDefinition( + entityClass = KeyMeta::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(KeyMeta::tags), + ), + GroupEntityModificationDefinition( + entityClass = Tag::class, + revisionTypes = listOf(RevisionType.ADD, RevisionType.DEL), + ), + ), + ), + + KEY_NAME_EDIT( + listOf(ActivityType.KEY_NAME_EDIT, ActivityType.COMPLEX_EDIT), + listOf( + GroupEntityModificationDefinition( + entityClass = Key::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(Key::name, Key::namespace), + ), + GroupEntityModificationDefinition( + entityClass = Namespace::class, + revisionTypes = listOf(RevisionType.ADD, RevisionType.DEL), + ), + ), + ), + + KEY_DELETE( + listOf(ActivityType.KEY_DELETE), + listOf( + GroupEntityModificationDefinition( + entityClass = Key::class, + revisionTypes = listOf(RevisionType.DEL), + ), + ), + ), + + KEY_CREATE( + listOf(ActivityType.CREATE_KEY), + listOf( + GroupEntityModificationDefinition( + entityClass = Key::class, + revisionTypes = listOf(RevisionType.ADD), + ), + GroupEntityModificationDefinition( + entityClass = KeyMeta::class, + revisionTypes = listOf(RevisionType.ADD), + ), + ), + ), + + IMPORT( + listOf(ActivityType.IMPORT), + listOf( + GroupEntityModificationDefinition( + entityClass = Key::class, + revisionTypes = listOf(RevisionType.ADD), + ), + GroupEntityModificationDefinition( + entityClass = KeyMeta::class, + revisionTypes = listOf(RevisionType.ADD, RevisionType.MOD), + modificationProps = listOf(KeyMeta::custom, KeyMeta::description), + ), + GroupEntityModificationDefinition( + entityClass = Translation::class, + revisionTypes = listOf(RevisionType.ADD), + ), + GroupEntityModificationDefinition( + entityClass = Namespace::class, + revisionTypes = listOf(RevisionType.ADD, RevisionType.DEL), + ), + ), + ), + + CREATE_LANGUAGE( + listOf(ActivityType.CREATE_LANGUAGE), + listOf( + GroupEntityModificationDefinition( + entityClass = Language::class, + revisionTypes = listOf(RevisionType.ADD), + ), + ), + ), + + EDIT_LANGUAGE( + listOf(ActivityType.EDIT_LANGUAGE), + listOf( + GroupEntityModificationDefinition( + entityClass = Language::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(Language::name, Language::tag, Language::originalName, Language::flagEmoji), + ), + ), + ), + + DELETE_LANGUAGE( + listOf(ActivityType.DELETE_LANGUAGE), + listOf( + GroupEntityModificationDefinition( + entityClass = Language::class, + revisionTypes = listOf(RevisionType.DEL), + ), + ), + ), + + CREATE_PROJECT( + listOf(ActivityType.CREATE_PROJECT), + listOf( + GroupEntityModificationDefinition( + entityClass = Project::class, + revisionTypes = listOf(RevisionType.ADD), + ), + ), + ), + + EDIT_PROJECT( + listOf(ActivityType.EDIT_PROJECT), + listOf( + GroupEntityModificationDefinition( + entityClass = Project::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = + listOf( + Project::name, + Project::description, + Project::baseLanguage, + Project::defaultNamespace, + Project::avatarHash, + ), + ), + ), + ), + + NAMESPACE_EDIT( + listOf(ActivityType.NAMESPACE_EDIT, ActivityType.BATCH_SET_KEYS_NAMESPACE), + listOf( + GroupEntityModificationDefinition( + entityClass = Namespace::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(Namespace::name), + ), + ), + ), + + BATCH_PRE_TRANSLATE_BY_TM( + listOf(ActivityType.BATCH_PRE_TRANSLATE_BY_TM), + listOf( + GroupEntityModificationDefinition( + entityClass = Translation::class, + revisionTypes = listOf(RevisionType.MOD, RevisionType.ADD), + modificationProps = listOf(Translation::state, Translation::text, Translation::outdated, Translation::auto), + ), + ), + ), + + BATCH_MACHINE_TRANSLATE( + listOf(ActivityType.BATCH_MACHINE_TRANSLATE), + listOf( + GroupEntityModificationDefinition( + entityClass = Translation::class, + revisionTypes = listOf(RevisionType.MOD, RevisionType.ADD), + modificationProps = listOf(Translation::state, Translation::text, Translation::outdated, Translation::auto), + ), + ), + ), + + AUTO_TRANSLATE( + listOf(ActivityType.AUTO_TRANSLATE), + listOf( + GroupEntityModificationDefinition( + entityClass = Translation::class, + revisionTypes = listOf(RevisionType.MOD, RevisionType.ADD), + modificationProps = listOf(Translation::state, Translation::text, Translation::outdated, Translation::auto), + ), + ), + ), + + BATCH_CLEAR_TRANSLATIONS( + listOf(ActivityType.BATCH_CLEAR_TRANSLATIONS), + listOf( + GroupEntityModificationDefinition( + entityClass = Translation::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(Translation::state, Translation::text, Translation::outdated, Translation::auto), + allowedValues = + mapOf( + Translation::text to null, + Translation::state to null, + Translation::outdated to false, + Translation::auto to false, + ), + ), + ), + ), + + BATCH_COPY_TRANSLATIONS( + listOf(ActivityType.BATCH_COPY_TRANSLATIONS), + listOf( + GroupEntityModificationDefinition( + entityClass = Translation::class, + revisionTypes = listOf(RevisionType.MOD, RevisionType.ADD), + modificationProps = listOf(Translation::state, Translation::text, Translation::outdated, Translation::auto), + ), + ), + ), + + BATCH_SET_TRANSLATION_STATE( + listOf(ActivityType.BATCH_SET_TRANSLATION_STATE), + listOf( + GroupEntityModificationDefinition( + entityClass = Translation::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(Translation::state, Translation::outdated, Translation::auto), + ), + ), + ), + + CONTENT_DELIVERY_CONFIG_CREATE( + listOf(ActivityType.CONTENT_DELIVERY_CONFIG_CREATE), + listOf( + GroupEntityModificationDefinition( + entityClass = ContentDeliveryConfig::class, + revisionTypes = listOf(RevisionType.ADD), + ), + ), + ), + + CONTENT_DELIVERY_CONFIG_UPDATE( + listOf(ActivityType.CONTENT_DELIVERY_CONFIG_UPDATE), + listOf( + GroupEntityModificationDefinition( + entityClass = ContentDeliveryConfig::class, + revisionTypes = listOf(RevisionType.MOD), + ), + ), + ), + + CONTENT_DELIVERY_CONFIG_DELETE( + listOf(ActivityType.CONTENT_DELIVERY_CONFIG_UPDATE), + listOf( + GroupEntityModificationDefinition( + entityClass = ContentDeliveryConfig::class, + revisionTypes = listOf(RevisionType.DEL), + ), + ), + ), + + CONTENT_STORAGE_CREATE( + listOf(ActivityType.CONTENT_STORAGE_CREATE), + listOf( + GroupEntityModificationDefinition( + entityClass = ContentStorage::class, + revisionTypes = listOf(RevisionType.ADD), + ), + ), + ), + + CONTENT_STORAGE_UPDATE( + listOf(ActivityType.CONTENT_STORAGE_UPDATE), + listOf( + GroupEntityModificationDefinition( + entityClass = ContentStorage::class, + revisionTypes = listOf(RevisionType.MOD), + ), + ), + ), + + CONTENT_STORAGE_DELETE( + listOf(ActivityType.CONTENT_STORAGE_DELETE), + listOf( + GroupEntityModificationDefinition( + entityClass = ContentStorage::class, + revisionTypes = listOf(RevisionType.DEL), + ), + ), + ), + + WEBHOOK_CONFIG_CREATE( + listOf(ActivityType.WEBHOOK_CONFIG_CREATE), + listOf( + GroupEntityModificationDefinition( + entityClass = WebhookConfig::class, + revisionTypes = listOf(RevisionType.ADD), + ), + ), + ), + + WEBHOOK_CONFIG_UPDATE( + listOf(ActivityType.WEBHOOK_CONFIG_CREATE), + listOf( + GroupEntityModificationDefinition( + entityClass = WebhookConfig::class, + revisionTypes = listOf(RevisionType.MOD), + ), + ), + ), + + WEBHOOK_CONFIG_DELETE( + listOf(ActivityType.WEBHOOK_CONFIG_CREATE), + listOf( + GroupEntityModificationDefinition( + entityClass = WebhookConfig::class, + revisionTypes = listOf(RevisionType.DEL), + ), + ), + ), +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/GroupEntityModificationDefinition.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/GroupEntityModificationDefinition.kt new file mode 100644 index 0000000000..5b151533ee --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/GroupEntityModificationDefinition.kt @@ -0,0 +1,12 @@ +package io.tolgee.activity.groups + +import io.tolgee.activity.data.RevisionType +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 + +class GroupEntityModificationDefinition( + val entityClass: KClass, + val revisionTypes: List, + val modificationProps: List>? = null, + val allowedValues: Map, Any?>? = null, +) diff --git a/backend/data/src/main/kotlin/io/tolgee/dtos/request/key/EditKeyDto.kt b/backend/data/src/main/kotlin/io/tolgee/dtos/request/key/EditKeyDto.kt index 6b47404816..e707c8bf66 100644 --- a/backend/data/src/main/kotlin/io/tolgee/dtos/request/key/EditKeyDto.kt +++ b/backend/data/src/main/kotlin/io/tolgee/dtos/request/key/EditKeyDto.kt @@ -14,7 +14,7 @@ data class EditKeyDto( @field:Length(max = 2000) var name: String = "", @field:Length(max = ValidationConstants.MAX_NAMESPACE_LENGTH) - @Schema(description = "The namespace of the key. (When empty or null default namespace will be used)") + @Schema(description = "The namespace of the key. (When empty or null, no namespace will be used)") @JsonProperty(access = JsonProperty.Access.READ_ONLY) var namespace: String? = null, @Size(max = 2000) diff --git a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityGroup.kt b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityGroup.kt new file mode 100644 index 0000000000..9bc800e98a --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityGroup.kt @@ -0,0 +1,119 @@ +package io.tolgee.model.activity + +import io.hypersistence.utils.hibernate.type.json.JsonBinaryType +import io.tolgee.activity.data.ActivityType +import io.tolgee.component.CurrentDateProvider +import io.tolgee.model.batch.BatchJob +import io.tolgee.model.batch.BatchJobChunkExecution +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.EntityListeners +import jakarta.persistence.EnumType +import jakarta.persistence.Enumerated +import jakarta.persistence.FetchType +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id +import jakarta.persistence.Index +import jakarta.persistence.OneToMany +import jakarta.persistence.OneToOne +import jakarta.persistence.PrePersist +import jakarta.persistence.SequenceGenerator +import jakarta.persistence.Table +import jakarta.persistence.Temporal +import jakarta.persistence.TemporalType +import org.hibernate.annotations.Type +import org.springframework.beans.factory.ObjectFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Configurable +import java.util.* + +@Entity +@Table( + indexes = [ + Index(columnList = "projectId"), + Index(columnList = "authorId"), + Index(columnList = "type"), + ], +) +@EntityListeners(ActivityGroup.Companion.ActivityRevisionListener::class) +class ActivityGroup : java.io.Serializable { + @Id + @SequenceGenerator( + name = "activitySequenceGenerator", + sequenceName = "activity_sequence", + initialValue = 0, + allocationSize = 10, + ) + @GeneratedValue( + strategy = GenerationType.SEQUENCE, + generator = "activitySequenceGenerator", + ) + val id: Long = 0 + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "timestamp", nullable = false, updatable = false) + lateinit var timestamp: Date + + /** + * We don't want a foreign key, since user could have been deleted + */ + var authorId: Long? = null + + @Column(columnDefinition = "jsonb") + @Type(JsonBinaryType::class) + var meta: MutableMap? = null + + @Enumerated(EnumType.STRING) + var type: ActivityType? = null + + /** + * Project of the change + */ + var projectId: Long? = null + + @OneToMany(mappedBy = "activityRevision") + var describingRelations: MutableList = mutableListOf() + + @OneToMany(mappedBy = "activityRevision") + var modifiedEntities: MutableList = mutableListOf() + + /** + * For chunked jobs, this field is set for every chunk. + * When job is running, each chunk has it's own activity revision. + * When job is finished, all the chunks revisions are merged into one revision and + * this field is set to null. + * + * Instead, [batchJob] is set. + */ + @OneToOne(fetch = FetchType.LAZY) + var batchJobChunkExecution: BatchJobChunkExecution? = null + + @OneToOne(fetch = FetchType.LAZY) + var batchJob: BatchJob? = null + + /** + * The instance is created in the Holder by default, but it is not initialized by the interceptor, + * so projectId and authorId might be null. + * + * This flag is set to true when the instance is initialized by the interceptor. + */ + @Transient + var isInitializedByInterceptor: Boolean = false + + @Transient + var cancelledBatchJobExecutionCount: Int? = null + + companion object { + @Configurable + class ActivityRevisionListener { + @Autowired + lateinit var provider: ObjectFactory + + @PrePersist + fun preRemove(activityRevision: ActivityGroup) { + activityRevision.timestamp = provider.`object`.date + } + } + } +} diff --git a/file b/file deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/settings.gradle b/settings.gradle index 7ef8cb7d50..9bcde28d03 100644 --- a/settings.gradle +++ b/settings.gradle @@ -70,6 +70,7 @@ dependencyResolutionManagement { library('micrometerPrometheus', "io.micrometer:micrometer-registry-prometheus:1.9.12") library('mailjet', "com.mailjet:mailjet-client:5.2.5") library('azureBlob', 'com.azure.spring:spring-cloud-azure-starter-storage-blob:5.11.0') + library('commonsText', 'org.apache.commons:commons-text:1.10.0') } } } diff --git a/webapp/src/service/apiSchema.generated.ts b/webapp/src/service/apiSchema.generated.ts index ca313baaa5..409a4f4e9e 100644 --- a/webapp/src/service/apiSchema.generated.ts +++ b/webapp/src/service/apiSchema.generated.ts @@ -165,7 +165,7 @@ export interface paths { put: operations["store"]; }; "/v2/projects/{projectId}/batch-jobs/{id}/cancel": { - /** Stops batch opperation if possible. */ + /** Stops batch operation if possible. */ put: operations["cancel"]; }; "/v2/projects/{projectId}/translations/{translationId}/set-state/{state}": { @@ -267,6 +267,15 @@ export interface paths { put: operations["uploadAvatar_2"]; delete: operations["removeAvatar_2"]; }; + "/v2/notifications/preferences/project/{id}": { + get: operations["getPerProjectPreferences"]; + put: operations["updatePerProjectPreferences"]; + delete: operations["deletePerProjectPreferences"]; + }; + "/v2/notifications/preferences/global": { + get: operations["getGlobalPreferences"]; + put: operations["updateGlobalPreferences"]; + }; "/v2/ee-license/set-license-key": { put: operations["setLicenseKey"]; }; @@ -471,6 +480,27 @@ export interface paths { get: operations["getAll_10"]; post: operations["create_12"]; }; + "/v2/notifications/unmark-as-done": { + post: operations["unmarkNotificationsAsDone"]; + }; + "/v2/notifications/preferences/project/{id}/subscribe": { + post: operations["subscribeToProject"]; + }; + "/v2/notifications/mark-as-unread": { + post: operations["markNotificationsAsUnread"]; + }; + "/v2/notifications/mark-as-read": { + post: operations["markNotificationsAsRead"]; + }; + "/v2/notifications/mark-as-read/all": { + post: operations["markAllNotificationsAsRead"]; + }; + "/v2/notifications/mark-as-done": { + post: operations["markNotificationsAsDone"]; + }; + "/v2/notifications/mark-as-done/all": { + post: operations["markAllNotificationsAsDone"]; + }; "/v2/image-upload": { post: operations["upload"]; }; @@ -523,6 +553,10 @@ export interface paths { "/v2/public/scope-info/hierarchy": { get: operations["getHierarchy"]; }; + "/v2/public/machine-translation-providers": { + /** Get machine translation providers */ + get: operations["getInfo_3"]; + }; "/v2/public/initial-data": { /** Returns initial data required by the UI to load */ get: operations["get_1"]; @@ -687,11 +721,17 @@ export interface paths { /** Returns all organization projects the user has access to */ get: operations["getAllProjects_1"]; }; + "/v2/notifications": { + get: operations["getNotifications"]; + }; + "/v2/notifications/preferences": { + get: operations["getAllPreferences"]; + }; "/v2/invitations/{code}/accept": { get: operations["acceptInvitation"]; }; "/v2/ee-license/info": { - get: operations["getInfo_3"]; + get: operations["getInfo_4"]; }; "/v2/api-keys/{keyId}": { /** Returns specific API key info */ @@ -865,14 +905,6 @@ export interface components { | "content-delivery.publish" | "webhooks.manage" )[]; - /** - * @deprecated - * @description Deprecated (use translateLanguageIds). - * - * List of languages current user has TRANSLATE permission to. If null, all languages edition is permitted. - * @example 200001,200004 - */ - permittedLanguageIds?: number[]; /** * @description List of languages user can translate to. If null, all languages editing is permitted. * @example 200001,200004 @@ -883,6 +915,14 @@ export interface components { * @example 200001,200004 */ stateChangeLanguageIds?: number[]; + /** + * @deprecated + * @description Deprecated (use translateLanguageIds). + * + * List of languages current user has TRANSLATE permission to. If null, all languages edition is permitted. + * @example 200001,200004 + */ + permittedLanguageIds?: number[]; }; LanguageModel: { /** Format: int64 */ @@ -1775,15 +1815,15 @@ export interface components { token: string; /** Format: int64 */ id: number; + description: string; /** Format: int64 */ createdAt: number; /** Format: int64 */ updatedAt: number; /** Format: int64 */ - lastUsedAt?: number; - /** Format: int64 */ expiresAt?: number; - description: string; + /** Format: int64 */ + lastUsedAt?: number; }; SetOrganizationRoleDto: { roleType: "MEMBER" | "OWNER"; @@ -1831,6 +1871,23 @@ export interface components { invitedUserName?: string; invitedUserEmail?: string; }; + NotificationPreferencesDto: { + /** @description List of notification types the user does not want to receive. */ + disabledNotifications: ( + | "ACTIVITY_LANGUAGES_CREATED" + | "ACTIVITY_KEYS_CREATED" + | "ACTIVITY_KEYS_UPDATED" + | "ACTIVITY_KEYS_SCREENSHOTS_UPLOADED" + | "ACTIVITY_SOURCE_STRINGS_UPDATED" + | "ACTIVITY_TRANSLATIONS_UPDATED" + | "ACTIVITY_TRANSLATION_OUTDATED" + | "ACTIVITY_TRANSLATION_REVIEWED" + | "ACTIVITY_TRANSLATION_UNREVIEWED" + | "ACTIVITY_NEW_COMMENTS" + | "ACTIVITY_COMMENTS_MENTION" + | "BATCH_JOB_ERRORED" + )[]; + }; SetLicenseKeyDto: { licenseKey: string; }; @@ -1920,17 +1977,17 @@ export interface components { key: string; /** Format: int64 */ id: number; - projectName: string; userFullName?: string; + projectName: string; + description: string; username?: string; /** Format: int64 */ - lastUsedAt?: number; - scopes: string[]; + projectId: number; /** Format: int64 */ expiresAt?: number; /** Format: int64 */ - projectId: number; - description: string; + lastUsedAt?: number; + scopes: string[]; }; SuperTokenRequest: { /** @description Has to be provided when TOTP enabled */ @@ -2445,7 +2502,8 @@ export interface components { | "USER_IS_NOT_OWNER_OF_ORGANIZATION" | "PAK_CREATED_FOR_DIFFERENT_PROJECT" | "CUSTOM_SLUG_IS_ONLY_APPLICABLE_FOR_CUSTOM_STORAGE" - | "INVALID_SLUG_FORMAT"; + | "INVALID_SLUG_FORMAT" + | "BATCH_JOB_CANCELLATION_TIMEOUT"; params?: { [key: string]: unknown }[]; }; UntagKeysRequest: { @@ -2829,6 +2887,16 @@ export interface components { | "webhooks.manage"; requires: components["schemas"]["HierarchyItem"][]; }; + MachineTranslationProviderModel: { + /** + * @description BCP 47 tags of languages supported by the translation service. When null, all possible languages are supported. + * + * Please note that Tolgee tries to fall back to a higher subtag if the subtag is not supported. + * + * E.g., if `pt-BR` is not supported. Tolgee fallbacks to `pt`. + */ + supportedLanguages?: string[]; + }; AnnouncementDto: { type: | "FEATURE_BATCH_OPERATIONS" @@ -2850,6 +2918,8 @@ export interface components { languageTag?: string; eeSubscription?: components["schemas"]["EeSubscriptionModel"]; announcement?: components["schemas"]["AnnouncementDto"]; + /** Format: int32 */ + unreadNotifications?: number; }; MtServiceDTO: { enabled: boolean; @@ -2906,11 +2976,11 @@ export interface components { */ currentUserRole?: "MEMBER" | "OWNER"; basePermissions: components["schemas"]["PermissionModel"]; - avatar?: components["schemas"]["Avatar"]; - /** @example btforg */ - slug: string; /** @example This is a beautiful organization full of beautiful and clever people */ description?: string; + /** @example btforg */ + slug: string; + avatar?: components["schemas"]["Avatar"]; }; PublicBillingConfigurationDTO: { enabled: boolean; @@ -3020,9 +3090,9 @@ export interface components { /** Format: int64 */ id: number; baseTranslation?: string; - translation?: string; description?: string; namespace?: string; + translation?: string; }; KeySearchSearchResultModel: { view?: components["schemas"]["KeySearchResultView"]; @@ -3030,9 +3100,9 @@ export interface components { /** Format: int64 */ id: number; baseTranslation?: string; - translation?: string; description?: string; namespace?: string; + translation?: string; }; PagedModelKeySearchSearchResultModel: { _embedded?: { @@ -3105,62 +3175,2359 @@ export interface components { avatar?: components["schemas"]["Avatar"]; deleted: boolean; }; - ProjectActivityModel: { - /** Format: int64 */ - revisionId: number; - /** Format: int64 */ - timestamp: number; - type: - | "UNKNOWN" - | "SET_TRANSLATION_STATE" - | "SET_TRANSLATIONS" - | "DISMISS_AUTO_TRANSLATED_STATE" - | "SET_OUTDATED_FLAG" - | "TRANSLATION_COMMENT_ADD" - | "TRANSLATION_COMMENT_DELETE" - | "TRANSLATION_COMMENT_EDIT" - | "TRANSLATION_COMMENT_SET_STATE" - | "SCREENSHOT_DELETE" - | "SCREENSHOT_ADD" - | "KEY_TAGS_EDIT" - | "KEY_NAME_EDIT" - | "KEY_DELETE" - | "CREATE_KEY" - | "COMPLEX_EDIT" - | "IMPORT" - | "CREATE_LANGUAGE" - | "EDIT_LANGUAGE" - | "DELETE_LANGUAGE" - | "CREATE_PROJECT" - | "EDIT_PROJECT" - | "NAMESPACE_EDIT" - | "BATCH_PRE_TRANSLATE_BY_TM" - | "BATCH_MACHINE_TRANSLATE" - | "AUTO_TRANSLATE" - | "BATCH_CLEAR_TRANSLATIONS" - | "BATCH_COPY_TRANSLATIONS" - | "BATCH_SET_TRANSLATION_STATE" - | "BATCH_TAG_KEYS" - | "BATCH_UNTAG_KEYS" - | "BATCH_SET_KEYS_NAMESPACE" - | "AUTOMATION" - | "CONTENT_DELIVERY_CONFIG_CREATE" - | "CONTENT_DELIVERY_CONFIG_UPDATE" - | "CONTENT_DELIVERY_CONFIG_DELETE" - | "CONTENT_STORAGE_CREATE" - | "CONTENT_STORAGE_UPDATE" - | "CONTENT_STORAGE_DELETE" - | "WEBHOOK_CONFIG_CREATE" - | "WEBHOOK_CONFIG_UPDATE" - | "WEBHOOK_CONFIG_DELETE"; - author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: { - [key: string]: components["schemas"]["ModifiedEntityModel"][]; - }; - meta?: { [key: string]: { [key: string]: unknown } }; - counts?: { [key: string]: number }; - params?: { [key: string]: unknown }; - }; + ProjectActivityModel: + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; PropertyModification: { old?: { [key: string]: unknown }; new?: { [key: string]: unknown }; @@ -3569,15 +5936,15 @@ export interface components { user: components["schemas"]["SimpleUserAccountModel"]; /** Format: int64 */ id: number; + description: string; /** Format: int64 */ createdAt: number; /** Format: int64 */ updatedAt: number; /** Format: int64 */ - lastUsedAt?: number; - /** Format: int64 */ expiresAt?: number; - description: string; + /** Format: int64 */ + lastUsedAt?: number; }; OrganizationRequestParamsDto: { filterCurrentUserOwner: boolean; @@ -3688,6 +6055,44 @@ export interface components { projectsWithDirectPermission: components["schemas"]["SimpleProjectModel"][]; avatar?: components["schemas"]["Avatar"]; }; + SimpleModifiedEntityView: { + entityClass: string; + /** Format: int64 */ + entityId: number; + exists?: boolean; + modifications: { + [key: string]: components["schemas"]["PropertyModification"]; + }; + description?: { [key: string]: { [key: string]: unknown } }; + describingRelations?: { + [key: string]: components["schemas"]["ExistenceEntityDescription"]; + }; + }; + UserNotificationModel: { + /** Format: int64 */ + id: number; + type: + | "ACTIVITY_LANGUAGES_CREATED" + | "ACTIVITY_KEYS_CREATED" + | "ACTIVITY_KEYS_UPDATED" + | "ACTIVITY_KEYS_SCREENSHOTS_UPLOADED" + | "ACTIVITY_SOURCE_STRINGS_UPDATED" + | "ACTIVITY_TRANSLATIONS_UPDATED" + | "ACTIVITY_TRANSLATION_OUTDATED" + | "ACTIVITY_TRANSLATION_REVIEWED" + | "ACTIVITY_TRANSLATION_UNREVIEWED" + | "ACTIVITY_NEW_COMMENTS" + | "ACTIVITY_COMMENTS_MENTION" + | "BATCH_JOB_ERRORED"; + project?: components["schemas"]["SimpleProjectModel"]; + batchJob?: components["schemas"]["BatchJobModel"]; + modifiedEntities?: components["schemas"]["SimpleModifiedEntityView"][]; + unread: boolean; + /** Format: date-time */ + markedDoneAt?: string; + /** Format: date-time */ + lastUpdated: string; + }; ApiKeyWithLanguagesModel: { /** * @deprecated @@ -3696,17 +6101,17 @@ export interface components { permittedLanguageIds?: number[]; /** Format: int64 */ id: number; - projectName: string; userFullName?: string; + projectName: string; + description: string; username?: string; /** Format: int64 */ - lastUsedAt?: number; - scopes: string[]; + projectId: number; /** Format: int64 */ expiresAt?: number; /** Format: int64 */ - projectId: number; - description: string; + lastUsedAt?: number; + scopes: string[]; }; PagedModelUserAccountModel: { _embedded?: { @@ -3732,18 +6137,2398 @@ export interface components { /** @description IDs of keys to delete */ ids: number[]; }; - }; -} - -export interface operations { - /** Returns information about currently authenticated user. */ - getInfo_2: { - responses: { - /** OK */ - 200: { - content: { - "application/json": components["schemas"]["PrivateUserAccountModel"]; - }; + ProjectActivityUnknownModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivitySetTranslationStateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivitySetTranslationsModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityDismissAutoTranslatedStateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivitySetOutdatedFlagModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityTranslationCommentAddModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityTranslationCommentDeleteModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityTranslationCommentEditModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityTranslationCommentSetStateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityScreenshotDeleteModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityScreenshotAddModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityKeyTagsEditModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityKeyNameEditModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityKeyDeleteModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityCreateKeyModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityComplexEditModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityImportModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityCreateLanguageModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityEditLanguageModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityDeleteLanguageModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityCreateProjectModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityEditProjectModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityNamespaceEditModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityBatchPreTranslateByTmModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityBatchMachineTranslateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityAutoTranslateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityBatchClearTranslationsModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityBatchCopyTranslationsModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityBatchSetTranslationStateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityBatchTagKeysModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityBatchUntagKeysModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityBatchSetKeysNamespaceModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityAutomationModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityContentDeliveryConfigCreateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityContentDeliveryConfigUpdateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityContentDeliveryConfigDeleteModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityContentStorageCreateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityContentStorageUpdateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityContentStorageDeleteModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityWebhookConfigCreateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityWebhookConfigUpdateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityWebhookConfigDeleteModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + KeyModifiedEntity: { + name?: { + old?: string; + new?: string; + }; + pluralArgName?: { + old?: string; + new?: string; + }; + namespace?: { + old?: { + entityClass?: string; + /** Format: int64 */ + entityId?: number; + data?: { + name?: string; + }; + }; + new?: { + entityClass?: string; + /** Format: int64 */ + entityId?: number; + data?: { + name?: string; + }; + }; + }; + }; + }; +} + +export interface operations { + /** Returns information about currently authenticated user. */ + getInfo_2: { + responses: { + /** OK */ + 200: { + content: { + "application/json": components["schemas"]["PrivateUserAccountModel"]; + }; }; /** Bad Request */ 400: { @@ -6031,7 +10816,7 @@ export interface operations { }; }; }; - /** Stops batch opperation if possible. */ + /** Stops batch operation if possible. */ cancel: { parameters: { path: { @@ -6383,11 +11168,11 @@ export interface operations { filterKeyName?: string[]; /** Selects key with provided ID. Use this param multiple times to fetch more keys. */ filterKeyId?: number[]; - /** Selects only keys, where translation is missing in any language */ + /** Selects only keys for which the translation is missing in any returned language. It only filters for translations included in returned languages. */ filterUntranslatedAny?: boolean; /** Selects only keys, where translation is provided in any language */ filterTranslatedAny?: boolean; - /** Selects only keys, where translation is missing in specified language */ + /** Selects only keys where the translation is missing for the specified language. The specified language must be included in the returned languages. Otherwise, this filter doesn't apply. */ filterUntranslatedInLang?: string; /** Selects only keys, where translation is provided in specified language */ filterTranslatedInLang?: string; @@ -7575,6 +12360,197 @@ export interface operations { }; }; }; + getPerProjectPreferences: { + parameters: { + path: { + id: number; + }; + }; + responses: { + /** OK */ + 200: { + content: { + "application/json": components["schemas"]["NotificationPreferencesDto"]; + }; + }; + /** Bad Request */ + 400: { + content: { + "*/*": string; + }; + }; + /** Unauthorized */ + 401: { + content: { + "*/*": string; + }; + }; + /** Forbidden */ + 403: { + content: { + "*/*": string; + }; + }; + /** Not Found */ + 404: { + content: { + "*/*": string; + }; + }; + }; + }; + updatePerProjectPreferences: { + parameters: { + path: { + id: number; + }; + }; + responses: { + /** OK */ + 200: { + content: { + "application/json": components["schemas"]["NotificationPreferencesDto"]; + }; + }; + /** Bad Request */ + 400: { + content: { + "*/*": string; + }; + }; + /** Unauthorized */ + 401: { + content: { + "*/*": string; + }; + }; + /** Forbidden */ + 403: { + content: { + "*/*": string; + }; + }; + /** Not Found */ + 404: { + content: { + "*/*": string; + }; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["NotificationPreferencesDto"]; + }; + }; + }; + deletePerProjectPreferences: { + parameters: { + path: { + id: number; + }; + }; + responses: { + /** No Content */ + 204: never; + /** Bad Request */ + 400: { + content: { + "*/*": string; + }; + }; + /** Unauthorized */ + 401: { + content: { + "*/*": string; + }; + }; + /** Forbidden */ + 403: { + content: { + "*/*": string; + }; + }; + /** Not Found */ + 404: { + content: { + "*/*": string; + }; + }; + }; + }; + getGlobalPreferences: { + responses: { + /** OK */ + 200: { + content: { + "application/json": components["schemas"]["NotificationPreferencesDto"]; + }; + }; + /** Bad Request */ + 400: { + content: { + "*/*": string; + }; + }; + /** Unauthorized */ + 401: { + content: { + "*/*": string; + }; + }; + /** Forbidden */ + 403: { + content: { + "*/*": string; + }; + }; + /** Not Found */ + 404: { + content: { + "*/*": string; + }; + }; + }; + }; + updateGlobalPreferences: { + responses: { + /** OK */ + 200: { + content: { + "application/json": components["schemas"]["NotificationPreferencesDto"]; + }; + }; + /** Bad Request */ + 400: { + content: { + "*/*": string; + }; + }; + /** Unauthorized */ + 401: { + content: { + "*/*": string; + }; + }; + /** Forbidden */ + 403: { + content: { + "*/*": string; + }; + }; + /** Not Found */ + 404: { + content: { + "*/*": string; + }; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["NotificationPreferencesDto"]; + }; + }; + }; setLicenseKey: { responses: { /** OK */ @@ -8807,7 +13783,268 @@ export interface operations { /** OK */ 200: { content: { - "application/json": components["schemas"]["PagedModelKeyModel"]; + "application/json": components["schemas"]["PagedModelKeyModel"]; + }; + }; + /** Bad Request */ + 400: { + content: { + "*/*": string; + }; + }; + /** Unauthorized */ + 401: { + content: { + "*/*": string; + }; + }; + /** Forbidden */ + 403: { + content: { + "*/*": string; + }; + }; + /** Not Found */ + 404: { + content: { + "*/*": string; + }; + }; + }; + }; + create_2: { + parameters: { + path: { + projectId: number; + }; + }; + responses: { + /** Created */ + 201: { + content: { + "*/*": components["schemas"]["KeyWithDataModel"]; + }; + }; + /** Bad Request */ + 400: { + content: { + "*/*": string; + }; + }; + /** Unauthorized */ + 401: { + content: { + "*/*": string; + }; + }; + /** Forbidden */ + 403: { + content: { + "*/*": string; + }; + }; + /** Not Found */ + 404: { + content: { + "*/*": string; + }; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateKeyDto"]; + }; + }; + }; + /** Delete one or multiple keys by their IDs in request body. Useful for larger requests esxceeding allowed URL length. */ + delete_4: { + parameters: { + path: { + projectId: number; + }; + }; + responses: { + /** OK */ + 200: unknown; + /** Bad Request */ + 400: { + content: { + "*/*": string; + }; + }; + /** Unauthorized */ + 401: { + content: { + "*/*": string; + }; + }; + /** Forbidden */ + 403: { + content: { + "*/*": string; + }; + }; + /** Not Found */ + 404: { + content: { + "*/*": string; + }; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["DeleteKeysDto"]; + }; + }; + }; + list_1: { + parameters: { + query: { + /** Zero-based page index (0..N) */ + page?: number; + /** The size of the page to be returned */ + size?: number; + /** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + }; + path: { + projectId: number; + }; + }; + responses: { + /** OK */ + 200: { + content: { + "application/json": components["schemas"]["PagedModelContentStorageModel"]; + }; + }; + /** Bad Request */ + 400: { + content: { + "*/*": string; + }; + }; + /** Unauthorized */ + 401: { + content: { + "*/*": string; + }; + }; + /** Forbidden */ + 403: { + content: { + "*/*": string; + }; + }; + /** Not Found */ + 404: { + content: { + "*/*": string; + }; + }; + }; + }; + create_5: { + parameters: { + path: { + projectId: number; + }; + }; + responses: { + /** OK */ + 200: { + content: { + "application/json": components["schemas"]["ContentStorageModel"]; + }; + }; + /** Bad Request */ + 400: { + content: { + "*/*": string; + }; + }; + /** Unauthorized */ + 401: { + content: { + "*/*": string; + }; + }; + /** Forbidden */ + 403: { + content: { + "*/*": string; + }; + }; + /** Not Found */ + 404: { + content: { + "*/*": string; + }; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["ContentStorageRequest"]; + }; + }; + }; + /** Tests existing Content Storage with new configuration. (Uses existing secrets, if nulls provided) */ + testExisting: { + parameters: { + path: { + id: number; + projectId: number; + }; + }; + responses: { + /** OK */ + 200: { + content: { + "application/json": components["schemas"]["StorageTestResult"]; + }; + }; + /** Bad Request */ + 400: { + content: { + "*/*": string; + }; + }; + /** Unauthorized */ + 401: { + content: { + "*/*": string; + }; + }; + /** Forbidden */ + 403: { + content: { + "*/*": string; + }; + }; + /** Not Found */ + 404: { + content: { + "*/*": string; + }; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["ContentStorageRequest"]; + }; + }; + }; + test_1: { + parameters: { + path: { + projectId: number; + }; + }; + responses: { + /** OK */ + 200: { + content: { + "application/json": components["schemas"]["StorageTestResult"]; }; }; /** Bad Request */ @@ -8835,18 +14072,31 @@ export interface operations { }; }; }; + requestBody: { + content: { + "application/json": components["schemas"]["ContentStorageRequest"]; + }; + }; }; - create_2: { + list_2: { parameters: { + query: { + /** Zero-based page index (0..N) */ + page?: number; + /** The size of the page to be returned */ + size?: number; + /** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + }; path: { projectId: number; }; }; responses: { - /** Created */ - 201: { + /** OK */ + 200: { content: { - "*/*": components["schemas"]["KeyWithDataModel"]; + "application/json": components["schemas"]["PagedModelContentDeliveryConfigModel"]; }; }; /** Bad Request */ @@ -8874,14 +14124,8 @@ export interface operations { }; }; }; - requestBody: { - content: { - "application/json": components["schemas"]["CreateKeyDto"]; - }; - }; }; - /** Delete one or multiple keys by their IDs in request body. Useful for larger requests esxceeding allowed URL length. */ - delete_4: { + create_6: { parameters: { path: { projectId: number; @@ -8889,7 +14133,11 @@ export interface operations { }; responses: { /** OK */ - 200: unknown; + 200: { + content: { + "application/json": components["schemas"]["ContentDeliveryConfigModel"]; + }; + }; /** Bad Request */ 400: { content: { @@ -8917,20 +14165,12 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["DeleteKeysDto"]; + "application/json": components["schemas"]["ContentDeliveryConfigRequest"]; }; }; }; - list_1: { + untagKeys: { parameters: { - query: { - /** Zero-based page index (0..N) */ - page?: number; - /** The size of the page to be returned */ - size?: number; - /** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ - sort?: string[]; - }; path: { projectId: number; }; @@ -8939,7 +14179,7 @@ export interface operations { /** OK */ 200: { content: { - "application/json": components["schemas"]["PagedModelContentStorageModel"]; + "application/json": components["schemas"]["BatchJobModel"]; }; }; /** Bad Request */ @@ -8967,8 +14207,13 @@ export interface operations { }; }; }; + requestBody: { + content: { + "application/json": components["schemas"]["UntagKeysRequest"]; + }; + }; }; - create_5: { + tagKeys: { parameters: { path: { projectId: number; @@ -8978,7 +14223,7 @@ export interface operations { /** OK */ 200: { content: { - "application/json": components["schemas"]["ContentStorageModel"]; + "application/json": components["schemas"]["BatchJobModel"]; }; }; /** Bad Request */ @@ -9008,15 +14253,13 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["ContentStorageRequest"]; + "application/json": components["schemas"]["TagKeysRequest"]; }; }; }; - /** Tests existing Content Storage with new configuration. (Uses existing secrets, if nulls provided) */ - testExisting: { + setTranslationState_2: { parameters: { path: { - id: number; projectId: number; }; }; @@ -9024,7 +14267,7 @@ export interface operations { /** OK */ 200: { content: { - "application/json": components["schemas"]["StorageTestResult"]; + "application/json": components["schemas"]["BatchJobModel"]; }; }; /** Bad Request */ @@ -9054,11 +14297,11 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["ContentStorageRequest"]; + "application/json": components["schemas"]["SetTranslationsStateStateRequest"]; }; }; }; - test_1: { + setKeysNamespace: { parameters: { path: { projectId: number; @@ -9068,7 +14311,7 @@ export interface operations { /** OK */ 200: { content: { - "application/json": components["schemas"]["StorageTestResult"]; + "application/json": components["schemas"]["BatchJobModel"]; }; }; /** Bad Request */ @@ -9098,20 +14341,13 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["ContentStorageRequest"]; + "application/json": components["schemas"]["SetKeysNamespaceRequest"]; }; }; }; - list_2: { + /** Pre-translate provided keys to provided languages by TM. */ + translate_1: { parameters: { - query: { - /** Zero-based page index (0..N) */ - page?: number; - /** The size of the page to be returned */ - size?: number; - /** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ - sort?: string[]; - }; path: { projectId: number; }; @@ -9120,7 +14356,7 @@ export interface operations { /** OK */ 200: { content: { - "application/json": components["schemas"]["PagedModelContentDeliveryConfigModel"]; + "application/json": components["schemas"]["BatchJobModel"]; }; }; /** Bad Request */ @@ -9148,8 +14384,14 @@ export interface operations { }; }; }; + requestBody: { + content: { + "application/json": components["schemas"]["PreTranslationByTmRequest"]; + }; + }; }; - create_6: { + /** Translate provided keys to provided languages through primary MT provider. */ + machineTranslation: { parameters: { path: { projectId: number; @@ -9159,7 +14401,7 @@ export interface operations { /** OK */ 200: { content: { - "application/json": components["schemas"]["ContentDeliveryConfigModel"]; + "application/json": components["schemas"]["BatchJobModel"]; }; }; /** Bad Request */ @@ -9189,11 +14431,11 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["ContentDeliveryConfigRequest"]; + "application/json": components["schemas"]["MachineTranslationRequest"]; }; }; }; - untagKeys: { + deleteKeys: { parameters: { path: { projectId: number; @@ -9233,11 +14475,12 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["UntagKeysRequest"]; + "application/json": components["schemas"]["DeleteKeysRequest"]; }; }; }; - tagKeys: { + /** Copy translation values from one language to other languages. */ + copyTranslations: { parameters: { path: { projectId: number; @@ -9277,11 +14520,12 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["TagKeysRequest"]; + "application/json": components["schemas"]["CopyTranslationRequest"]; }; }; }; - setTranslationState_2: { + /** Clear translation values for provided keys in selected languages. */ + clearTranslations: { parameters: { path: { projectId: number; @@ -9321,12 +14565,19 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["SetTranslationsStateStateRequest"]; + "application/json": components["schemas"]["ClearTranslationsRequest"]; }; }; }; - setKeysNamespace: { + /** Prepares provided files to import. */ + addFiles: { parameters: { + query: { + /** When importing structured JSONs, you can set the delimiter which will be used in names of improted keys. */ + structureDelimiter?: string; + /** If true, for structured formats (like JSON) arrays are supported. e.g. Array object like {"hello": ["item1", "item2"]} will be imported as keys hello[0] = "item1" and hello[1] = "item2". */ + supportArrays?: boolean; + }; path: { projectId: number; }; @@ -9335,7 +14586,7 @@ export interface operations { /** OK */ 200: { content: { - "application/json": components["schemas"]["BatchJobModel"]; + "application/json": components["schemas"]["ImportAddFilesResultModel"]; }; }; /** Bad Request */ @@ -9365,12 +14616,14 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["SetKeysNamespaceRequest"]; + "multipart/form-data": { + files: string[]; + }; }; }; }; - /** Pre-translate provided keys to provided languages by TM. */ - translate_1: { + /** Deletes prepared import data. */ + cancelImport: { parameters: { path: { projectId: number; @@ -9378,11 +14631,7 @@ export interface operations { }; responses: { /** OK */ - 200: { - content: { - "application/json": components["schemas"]["BatchJobModel"]; - }; - }; + 200: unknown; /** Bad Request */ 400: { content: { @@ -9408,15 +14657,83 @@ export interface operations { }; }; }; - requestBody: { - content: { - "application/json": components["schemas"]["PreTranslationByTmRequest"]; - }; - }; }; - /** Translate provided keys to provided languages through primary MT provider. */ - machineTranslation: { + export: { parameters: { + query: { + /** + * Languages to be contained in export. + * + * If null, all languages are exported + */ + languages?: string[]; + /** Format to export to */ + format?: + | "JSON" + | "JSON_TOLGEE" + | "XLIFF" + | "PO" + | "APPLE_STRINGS_STRINGSDICT" + | "APPLE_XLIFF" + | "ANDROID_XML" + | "FLUTTER_ARB" + | "PROPERTIES" + | "YAML_RUBY" + | "YAML"; + /** + * Delimiter to structure file content. + * + * e.g. For key "home.header.title" would result in {"home": {"header": "title": {"Hello"}}} structure. + * + * When null, resulting file won't be structured. Works only for generic structured formats (e.g. JSON, YAML), + * specific formats like `YAML_RUBY` don't honor this parameter. + */ + structureDelimiter?: string; + /** Filter key IDs to be contained in export */ + filterKeyId?: number[]; + /** Filter key IDs not to be contained in export */ + filterKeyIdNot?: number[]; + /** Filter keys tagged by */ + filterTag?: string; + /** Filter keys with prefix */ + filterKeyPrefix?: string; + /** Filter translations with state. By default, all states except untranslated is exported. */ + filterState?: ( + | "UNTRANSLATED" + | "TRANSLATED" + | "REVIEWED" + | "DISABLED" + )[]; + /** Filter translations with namespace. By default, all namespaces everything are exported. To export default namespace, use empty string. */ + filterNamespace?: string[]; + /** + * If false, it doesn't return zip of files, but it returns single file. + * + * This is possible only when single language is exported. Otherwise it returns "400 - Bad Request" response. + */ + zip?: boolean; + /** + * Message format to be used for export. + * + * e.g. PHP_PO: Hello %s, ICU: Hello {name}. + * + * This property is honored only for generic formats like JSON or YAML. + * For specific formats like `YAML_RUBY` it's ignored. + */ + messageFormat?: + | "C_SPRINTF" + | "PHP_SPRINTF" + | "JAVA_STRING_FORMAT" + | "APPLE_SPRINTF" + | "RUBY_SPRINTF" + | "ICU"; + /** + * If true, for structured formats (like JSON) arrays are supported. + * + * e.g. Key hello[0] will be exported as {"hello": ["..."]} + */ + supportArrays?: boolean; + }; path: { projectId: number; }; @@ -9425,7 +14742,7 @@ export interface operations { /** OK */ 200: { content: { - "application/json": components["schemas"]["BatchJobModel"]; + "application/json": components["schemas"]["StreamingResponseBody"]; }; }; /** Bad Request */ @@ -9453,13 +14770,9 @@ export interface operations { }; }; }; - requestBody: { - content: { - "application/json": components["schemas"]["MachineTranslationRequest"]; - }; - }; }; - deleteKeys: { + /** Exports data (post). Useful when exceeding allowed URL size. */ + exportPost: { parameters: { path: { projectId: number; @@ -9469,7 +14782,7 @@ export interface operations { /** OK */ 200: { content: { - "application/json": components["schemas"]["BatchJobModel"]; + "application/json": components["schemas"]["StreamingResponseBody"]; }; }; /** Bad Request */ @@ -9499,24 +14812,20 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["DeleteKeysRequest"]; + "application/json": components["schemas"]["ExportParams"]; }; }; }; - /** Copy translation values from one language to other languages. */ - copyTranslations: { + /** Stores a bigMeta for a project */ + store_2: { parameters: { path: { projectId: number; }; }; - responses: { - /** OK */ - 200: { - content: { - "application/json": components["schemas"]["BatchJobModel"]; - }; - }; + responses: { + /** OK */ + 200: unknown; /** Bad Request */ 400: { content: { @@ -9544,22 +14853,31 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["CopyTranslationRequest"]; + "application/json": components["schemas"]["BigMetaDto"]; }; }; }; - /** Clear translation values for provided keys in selected languages. */ - clearTranslations: { + /** Returns translation comments of translation */ + getAll_5: { parameters: { path: { + translationId: number; projectId: number; }; + query: { + /** Zero-based page index (0..N) */ + page?: number; + /** The size of the page to be returned */ + size?: number; + /** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + }; }; responses: { /** OK */ 200: { content: { - "application/json": components["schemas"]["BatchJobModel"]; + "application/json": components["schemas"]["PagedModelTranslationCommentModel"]; }; }; /** Bad Request */ @@ -9587,30 +14905,19 @@ export interface operations { }; }; }; - requestBody: { - content: { - "application/json": components["schemas"]["ClearTranslationsRequest"]; - }; - }; }; - /** Prepares provided files to import. */ - addFiles: { + create_7: { parameters: { - query: { - /** When importing structured JSONs, you can set the delimiter which will be used in names of improted keys. */ - structureDelimiter?: string; - /** If true, for structured formats (like JSON) arrays are supported. e.g. Array object like {"hello": ["item1", "item2"]} will be imported as keys hello[0] = "item1" and hello[1] = "item2". */ - supportArrays?: boolean; - }; path: { + translationId: number; projectId: number; }; }; responses: { - /** OK */ - 200: { + /** Created */ + 201: { content: { - "application/json": components["schemas"]["ImportAddFilesResultModel"]; + "*/*": components["schemas"]["TranslationCommentModel"]; }; }; /** Bad Request */ @@ -9640,22 +14947,24 @@ export interface operations { }; requestBody: { content: { - "multipart/form-data": { - files: string[]; - }; + "application/json": components["schemas"]["TranslationCommentDto"]; }; }; }; - /** Deletes prepared import data. */ - cancelImport: { + /** Creates a translation comment. Empty translation is stored, when not exists. */ + create_9: { parameters: { path: { projectId: number; }; }; responses: { - /** OK */ - 200: unknown; + /** Created */ + 201: { + content: { + "*/*": components["schemas"]["TranslationWithCommentModel"]; + }; + }; /** Bad Request */ 400: { content: { @@ -9681,82 +14990,22 @@ export interface operations { }; }; }; + requestBody: { + content: { + "application/json": components["schemas"]["TranslationCommentWithLangKeyDto"]; + }; + }; }; - export: { + /** Suggests machine translations from translation memory. The result is always sorted by similarity, so sorting is not supported. */ + suggestTranslationMemory: { parameters: { query: { - /** - * Languages to be contained in export. - * - * If null, all languages are exported - */ - languages?: string[]; - /** Format to export to */ - format?: - | "JSON" - | "JSON_TOLGEE" - | "XLIFF" - | "PO" - | "APPLE_STRINGS_STRINGSDICT" - | "APPLE_XLIFF" - | "ANDROID_XML" - | "FLUTTER_ARB" - | "PROPERTIES" - | "YAML_RUBY" - | "YAML"; - /** - * Delimiter to structure file content. - * - * e.g. For key "home.header.title" would result in {"home": {"header": "title": {"Hello"}}} structure. - * - * When null, resulting file won't be structured. Works only for generic structured formats (e.g. JSON, YAML), - * specific formats like `YAML_RUBY` don't honor this parameter. - */ - structureDelimiter?: string; - /** Filter key IDs to be contained in export */ - filterKeyId?: number[]; - /** Filter key IDs not to be contained in export */ - filterKeyIdNot?: number[]; - /** Filter keys tagged by */ - filterTag?: string; - /** Filter keys with prefix */ - filterKeyPrefix?: string; - /** Filter translations with state. By default, all states except untranslated is exported. */ - filterState?: ( - | "UNTRANSLATED" - | "TRANSLATED" - | "REVIEWED" - | "DISABLED" - )[]; - /** Filter translations with namespace. By default, all namespaces everything are exported. To export default namespace, use empty string. */ - filterNamespace?: string[]; - /** - * If false, it doesn't return zip of files, but it returns single file. - * - * This is possible only when single language is exported. Otherwise it returns "400 - Bad Request" response. - */ - zip?: boolean; - /** - * Message format to be used for export. - * - * e.g. PHP_PO: Hello %s, ICU: Hello {name}. - * - * This property is honored only for generic formats like JSON or YAML. - * For specific formats like `YAML_RUBY` it's ignored. - */ - messageFormat?: - | "C_SPRINTF" - | "PHP_SPRINTF" - | "JAVA_STRING_FORMAT" - | "APPLE_SPRINTF" - | "RUBY_SPRINTF" - | "ICU"; - /** - * If true, for structured formats (like JSON) arrays are supported. - * - * e.g. Key hello[0] will be exported as {"hello": ["..."]} - */ - supportArrays?: boolean; + /** Zero-based page index (0..N) */ + page?: number; + /** The size of the page to be returned */ + size?: number; + /** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; }; path: { projectId: number; @@ -9766,7 +15015,7 @@ export interface operations { /** OK */ 200: { content: { - "application/json": components["schemas"]["StreamingResponseBody"]; + "application/json": components["schemas"]["PagedModelTranslationMemoryItemModel"]; }; }; /** Bad Request */ @@ -9794,9 +15043,14 @@ export interface operations { }; }; }; + requestBody: { + content: { + "application/json": components["schemas"]["SuggestRequestDto"]; + }; + }; }; - /** Exports data (post). Useful when exceeding allowed URL size. */ - exportPost: { + /** Suggests machine translations from enabled services. The results are streamed to the output in ndjson format. If an error occurs when for any service provider used, the error information is returned as a part of the result item, while the response has 200 status code. */ + suggestMachineTranslationsStreaming: { parameters: { path: { projectId: number; @@ -9806,7 +15060,7 @@ export interface operations { /** OK */ 200: { content: { - "application/json": components["schemas"]["StreamingResponseBody"]; + "application/x-ndjson": components["schemas"]["StreamingResponseBody"]; }; }; /** Bad Request */ @@ -9836,12 +15090,12 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["ExportParams"]; + "application/json": components["schemas"]["SuggestRequestDto"]; }; }; }; - /** Stores a bigMeta for a project */ - store_2: { + /** Suggests machine translations from enabled services */ + suggestMachineTranslations: { parameters: { path: { projectId: number; @@ -9849,7 +15103,11 @@ export interface operations { }; responses: { /** OK */ - 200: unknown; + 200: { + content: { + "application/json": components["schemas"]["SuggestResultModel"]; + }; + }; /** Bad Request */ 400: { content: { @@ -9877,15 +15135,13 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["BigMetaDto"]; + "application/json": components["schemas"]["SuggestRequestDto"]; }; }; }; - /** Returns translation comments of translation */ - getAll_5: { + getAll_7: { parameters: { path: { - translationId: number; projectId: number; }; query: { @@ -9901,7 +15157,7 @@ export interface operations { /** OK */ 200: { content: { - "application/json": components["schemas"]["PagedModelTranslationCommentModel"]; + "application/json": components["schemas"]["PagedModelLanguageModel"]; }; }; /** Bad Request */ @@ -9930,18 +15186,17 @@ export interface operations { }; }; }; - create_7: { + createLanguage: { parameters: { path: { - translationId: number; projectId: number; }; }; responses: { - /** Created */ - 201: { + /** OK */ + 200: { content: { - "*/*": components["schemas"]["TranslationCommentModel"]; + "application/json": components["schemas"]["LanguageModel"]; }; }; /** Bad Request */ @@ -9971,22 +15226,22 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["TranslationCommentDto"]; + "application/json": components["schemas"]["LanguageRequest"]; }; }; }; - /** Creates a translation comment. Empty translation is stored, when not exists. */ - create_9: { + getKeyScreenshots_1: { parameters: { path: { + keyId: number; projectId: number; }; }; responses: { - /** Created */ - 201: { + /** OK */ + 200: { content: { - "*/*": components["schemas"]["TranslationWithCommentModel"]; + "application/json": components["schemas"]["CollectionModelScreenshotModel"]; }; }; /** Bad Request */ @@ -10014,32 +15269,19 @@ export interface operations { }; }; }; - requestBody: { - content: { - "application/json": components["schemas"]["TranslationCommentWithLangKeyDto"]; - }; - }; }; - /** Suggests machine translations from translation memory. The result is always sorted by similarity, so sorting is not supported. */ - suggestTranslationMemory: { + uploadScreenshot_1: { parameters: { - query: { - /** Zero-based page index (0..N) */ - page?: number; - /** The size of the page to be returned */ - size?: number; - /** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ - sort?: string[]; - }; path: { + keyId: number; projectId: number; }; }; responses: { - /** OK */ - 200: { + /** Created */ + 201: { content: { - "application/json": components["schemas"]["PagedModelTranslationMemoryItemModel"]; + "*/*": components["schemas"]["ScreenshotModel"]; }; }; /** Bad Request */ @@ -10069,22 +15311,30 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["SuggestRequestDto"]; + "multipart/form-data": { + /** Format: binary */ + screenshot: string; + info?: components["schemas"]["ScreenshotInfoDto"]; + }; }; }; }; - /** Suggests machine translations from enabled services. The results are streamed to the output in ndjson format. If an error occurs when for any service provider used, the error information is returned as a part of the result item, while the response has 200 status code. */ - suggestMachineTranslationsStreaming: { + getAll_9: { parameters: { - path: { - projectId: number; + query: { + /** Zero-based page index (0..N) */ + page?: number; + /** The size of the page to be returned */ + size?: number; + /** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; }; }; responses: { /** OK */ 200: { content: { - "application/x-ndjson": components["schemas"]["StreamingResponseBody"]; + "application/json": components["schemas"]["PagedModelPatModel"]; }; }; /** Bad Request */ @@ -10112,24 +15362,13 @@ export interface operations { }; }; }; - requestBody: { - content: { - "application/json": components["schemas"]["SuggestRequestDto"]; - }; - }; }; - /** Suggests machine translations from enabled services */ - suggestMachineTranslations: { - parameters: { - path: { - projectId: number; - }; - }; + create_11: { responses: { - /** OK */ - 200: { + /** Created */ + 201: { content: { - "application/json": components["schemas"]["SuggestResultModel"]; + "*/*": components["schemas"]["RevealedPatModel"]; }; }; /** Bad Request */ @@ -10159,15 +15398,13 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["SuggestRequestDto"]; + "application/json": components["schemas"]["CreatePatDto"]; }; }; }; - getAll_7: { + /** Returns all organizations, which is current user allowed to view */ + getAll_10: { parameters: { - path: { - projectId: number; - }; query: { /** Zero-based page index (0..N) */ page?: number; @@ -10175,13 +15412,14 @@ export interface operations { size?: number; /** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ sort?: string[]; + params: components["schemas"]["OrganizationRequestParamsDto"]; }; }; responses: { /** OK */ 200: { content: { - "application/json": components["schemas"]["PagedModelLanguageModel"]; + "application/hal+json": components["schemas"]["PagedModelOrganizationModel"]; }; }; /** Bad Request */ @@ -10210,17 +15448,12 @@ export interface operations { }; }; }; - createLanguage: { - parameters: { - path: { - projectId: number; - }; - }; + create_12: { responses: { /** OK */ 200: { content: { - "application/json": components["schemas"]["LanguageModel"]; + "application/json": components["schemas"]["OrganizationModel"]; }; }; /** Bad Request */ @@ -10250,24 +15483,14 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["LanguageRequest"]; + "application/json": components["schemas"]["OrganizationDto"]; }; }; }; - getKeyScreenshots_1: { - parameters: { - path: { - keyId: number; - projectId: number; - }; - }; + unmarkNotificationsAsDone: { responses: { - /** OK */ - 200: { - content: { - "application/json": components["schemas"]["CollectionModelScreenshotModel"]; - }; - }; + /** No Content */ + 204: never; /** Bad Request */ 400: { content: { @@ -10293,19 +15516,23 @@ export interface operations { }; }; }; + requestBody: { + content: { + "application/json": number[]; + }; + }; }; - uploadScreenshot_1: { + subscribeToProject: { parameters: { path: { - keyId: number; - projectId: number; + id: number; }; }; responses: { - /** Created */ - 201: { + /** OK */ + 200: { content: { - "*/*": components["schemas"]["ScreenshotModel"]; + "application/json": string; }; }; /** Bad Request */ @@ -10333,34 +15560,11 @@ export interface operations { }; }; }; - requestBody: { - content: { - "multipart/form-data": { - /** Format: binary */ - screenshot: string; - info?: components["schemas"]["ScreenshotInfoDto"]; - }; - }; - }; }; - getAll_9: { - parameters: { - query: { - /** Zero-based page index (0..N) */ - page?: number; - /** The size of the page to be returned */ - size?: number; - /** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ - sort?: string[]; - }; - }; + markNotificationsAsUnread: { responses: { - /** OK */ - 200: { - content: { - "application/json": components["schemas"]["PagedModelPatModel"]; - }; - }; + /** No Content */ + 204: never; /** Bad Request */ 400: { content: { @@ -10386,15 +15590,16 @@ export interface operations { }; }; }; + requestBody: { + content: { + "application/json": number[]; + }; + }; }; - create_11: { + markNotificationsAsRead: { responses: { - /** Created */ - 201: { - content: { - "*/*": components["schemas"]["RevealedPatModel"]; - }; - }; + /** No Content */ + 204: never; /** Bad Request */ 400: { content: { @@ -10422,30 +15627,14 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["CreatePatDto"]; + "application/json": number[]; }; }; }; - /** Returns all organizations, which is current user allowed to view */ - getAll_10: { - parameters: { - query: { - /** Zero-based page index (0..N) */ - page?: number; - /** The size of the page to be returned */ - size?: number; - /** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ - sort?: string[]; - params: components["schemas"]["OrganizationRequestParamsDto"]; - }; - }; + markAllNotificationsAsRead: { responses: { - /** OK */ - 200: { - content: { - "application/hal+json": components["schemas"]["PagedModelOrganizationModel"]; - }; - }; + /** No Content */ + 204: never; /** Bad Request */ 400: { content: { @@ -10472,14 +15661,10 @@ export interface operations { }; }; }; - create_12: { + markNotificationsAsDone: { responses: { - /** OK */ - 200: { - content: { - "application/json": components["schemas"]["OrganizationModel"]; - }; - }; + /** No Content */ + 204: never; /** Bad Request */ 400: { content: { @@ -10507,7 +15692,37 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["OrganizationDto"]; + "application/json": number[]; + }; + }; + }; + markAllNotificationsAsDone: { + responses: { + /** No Content */ + 204: never; + /** Bad Request */ + 400: { + content: { + "*/*": string; + }; + }; + /** Unauthorized */ + 401: { + content: { + "*/*": string; + }; + }; + /** Forbidden */ + 403: { + content: { + "*/*": string; + }; + }; + /** Not Found */ + 404: { + content: { + "*/*": string; + }; }; }; }; @@ -11143,6 +16358,45 @@ export interface operations { }; }; }; + /** Get machine translation providers */ + getInfo_3: { + responses: { + /** OK */ + 200: { + content: { + "application/json": { + [ + key: string + ]: components["schemas"]["MachineTranslationProviderModel"]; + }; + }; + }; + /** Bad Request */ + 400: { + content: { + "*/*": string; + }; + }; + /** Unauthorized */ + 401: { + content: { + "*/*": string; + }; + }; + /** Forbidden */ + 403: { + content: { + "*/*": string; + }; + }; + /** Not Found */ + 404: { + content: { + "*/*": string; + }; + }; + }; + }; /** Returns initial data required by the UI to load */ get_1: { responses: { @@ -12268,11 +17522,11 @@ export interface operations { filterKeyName?: string[]; /** Selects key with provided ID. Use this param multiple times to fetch more keys. */ filterKeyId?: number[]; - /** Selects only keys, where translation is missing in any language */ + /** Selects only keys for which the translation is missing in any returned language. It only filters for translations included in returned languages. */ filterUntranslatedAny?: boolean; /** Selects only keys, where translation is provided in any language */ filterTranslatedAny?: boolean; - /** Selects only keys, where translation is missing in specified language */ + /** Selects only keys where the translation is missing for the specified language. The specified language must be included in the returned languages. Otherwise, this filter doesn't apply. */ filterUntranslatedInLang?: string; /** Selects only keys, where translation is provided in specified language */ filterTranslatedInLang?: string; @@ -12354,11 +17608,11 @@ export interface operations { filterKeyName?: string[]; /** Selects key with provided ID. Use this param multiple times to fetch more keys. */ filterKeyId?: number[]; - /** Selects only keys, where translation is missing in any language */ + /** Selects only keys for which the translation is missing in any returned language. It only filters for translations included in returned languages. */ filterUntranslatedAny?: boolean; /** Selects only keys, where translation is provided in any language */ filterTranslatedAny?: boolean; - /** Selects only keys, where translation is missing in specified language */ + /** Selects only keys where the translation is missing for the specified language. The specified language must be included in the returned languages. Otherwise, this filter doesn't apply. */ filterUntranslatedInLang?: string; /** Selects only keys, where translation is provided in specified language */ filterTranslatedInLang?: string; @@ -13176,6 +18430,87 @@ export interface operations { }; }; }; + getNotifications: { + parameters: { + query: { + status?: ("UNREAD" | "READ" | "DONE")[]; + /** Zero-based page index (0..N) */ + page?: number; + /** The size of the page to be returned */ + size?: number; + /** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + }; + }; + responses: { + /** OK */ + 200: { + content: { + "application/json": components["schemas"]["UserNotificationModel"][]; + }; + }; + /** Bad Request */ + 400: { + content: { + "*/*": string; + }; + }; + /** Unauthorized */ + 401: { + content: { + "*/*": string; + }; + }; + /** Forbidden */ + 403: { + content: { + "*/*": string; + }; + }; + /** Not Found */ + 404: { + content: { + "*/*": string; + }; + }; + }; + }; + getAllPreferences: { + responses: { + /** OK */ + 200: { + content: { + "application/json": { + [key: string]: components["schemas"]["NotificationPreferencesDto"]; + }; + }; + }; + /** Bad Request */ + 400: { + content: { + "*/*": string; + }; + }; + /** Unauthorized */ + 401: { + content: { + "*/*": string; + }; + }; + /** Forbidden */ + 403: { + content: { + "*/*": string; + }; + }; + /** Not Found */ + 404: { + content: { + "*/*": string; + }; + }; + }; + }; acceptInvitation: { parameters: { path: { @@ -13211,7 +18546,7 @@ export interface operations { }; }; }; - getInfo_3: { + getInfo_4: { responses: { /** OK */ 200: { From dab8b16b7962b995ce4b08a030af23f41ab62963 Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Thu, 30 May 2024 15:00:21 +0200 Subject: [PATCH 37/44] feat: Grouper --- .../io/tolgee/activity/ActivityService.kt | 5 ++++ .../activity/groups/ActivityGroupService.kt | 18 ++++++++++++ .../tolgee/activity/groups/ActivityGrouper.kt | 29 +++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupService.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGrouper.kt diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/ActivityService.kt b/backend/data/src/main/kotlin/io/tolgee/activity/ActivityService.kt index 71c2406fd9..59e6f02e66 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/ActivityService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/ActivityService.kt @@ -3,6 +3,7 @@ package io.tolgee.activity import com.fasterxml.jackson.databind.ObjectMapper import io.tolgee.activity.data.ActivityType import io.tolgee.activity.data.RevisionType +import io.tolgee.activity.groups.ActivityGroupService import io.tolgee.activity.views.ProjectActivityViewByPageableProvider import io.tolgee.activity.views.ProjectActivityViewByRevisionProvider import io.tolgee.dtos.queryResults.TranslationHistoryView @@ -29,6 +30,7 @@ class ActivityService( private val activityModifiedEntityRepository: ActivityModifiedEntityRepository, private val objectMapper: ObjectMapper, private val jdbcTemplate: JdbcTemplate, + private val activityGroupService: ActivityGroupService, ) : Logging { @Transactional fun storeActivityData( @@ -42,6 +44,9 @@ class ActivityService( persistedDescribingRelations(mergedActivityRevision) mergedActivityRevision.modifiedEntities = persistModifiedEntities(modifiedEntities) + + activityGroupService.addToGroup(activityRevision, modifiedEntities) + applicationContext.publishEvent(OnProjectActivityStoredEvent(this, mergedActivityRevision)) } diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupService.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupService.kt new file mode 100644 index 0000000000..8a7b6dc376 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupService.kt @@ -0,0 +1,18 @@ +package io.tolgee.activity.groups + +import io.tolgee.activity.ModifiedEntitiesType +import io.tolgee.model.activity.ActivityRevision +import org.springframework.context.ApplicationContext +import org.springframework.stereotype.Service + +@Service +class ActivityGroupService( + private val applicationContext: ApplicationContext, +) { + fun addToGroup( + activityRevision: ActivityRevision, + modifiedEntities: ModifiedEntitiesType, + ) { + ActivityGrouper(activityRevision, modifiedEntities, applicationContext).addToGroup() + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGrouper.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGrouper.kt new file mode 100644 index 0000000000..98ac011882 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGrouper.kt @@ -0,0 +1,29 @@ +package io.tolgee.activity.groups + +import io.tolgee.activity.ModifiedEntitiesType +import io.tolgee.model.activity.ActivityRevision +import org.springframework.context.ApplicationContext + +class ActivityGrouper( + activityRevision: ActivityRevision, + modifiedEntities: ModifiedEntitiesType, + applicationContext: ApplicationContext, +) { + fun addToGroup() { + } + + fun findGroupTypes() { + val type = type ?: return + + ActivityGroupType.values().filter { it.matches } + } + + private val ActivityGroupType.matches: Boolean + get() { + if (!this.sourceActivityTypes.contains(type)) { + return false + } + } + + private val type = activityRevision.type +} From 5fb7b3801553e79d5e96d73667abf0f250886763 Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Thu, 6 Jun 2024 15:48:31 +0200 Subject: [PATCH 38/44] fix: Add JOOQ, activity grouping stuff --- .../controllers/ProjectActivityController.kt | 14 ++ backend/app/build.gradle | 2 +- .../app/src/main/resources/application.yaml | 6 +- .../activity/RootActivityProviderTest.kt | 2 +- .../groups/ActivityGroupsCreationTest.kt | 231 ++++++++++++++++++ .../ModificationSchemaGeneratorTest.kt | 7 +- .../app/src/test/resources/application.yaml | 7 +- backend/data/build.gradle | 1 + .../activity/groups/ActivityGroupDto.kt | 10 + .../activity/groups/ActivityGroupService.kt | 111 +++++++++ .../activity/groups/ActivityGroupType.kt | 41 +++- .../tolgee/activity/groups/ActivityGrouper.kt | 105 +++++++- .../activity/groups/ActivityGroupsProvider.kt | 144 +++++++++++ .../GroupEntityModificationDefinition.kt | 2 + .../matchers/ActivityGroupValueMatcher.kt | 22 ++ .../groups/matchers/EqualsValueMatcher.kt | 30 +++ .../matchers/ModificationValueMatcher.kt | 29 +++ .../groups/matchers/NotNullValueMatcher.kt | 25 ++ .../dtos/queryResults/ActivityGroupView.kt | 13 + .../io/tolgee/model/activity/ActivityGroup.kt | 92 +------ .../tolgee/model/activity/ActivityRevision.kt | 5 + .../activity/ActivityGroupRepository.kt | 35 +++ .../main/resources/db/changelog/schema.xml | 34 +++ .../tests/src/test/resources/application.yaml | 6 +- settings.gradle | 1 + 25 files changed, 875 insertions(+), 100 deletions(-) create mode 100644 backend/app/src/test/kotlin/io/tolgee/activity/groups/ActivityGroupsCreationTest.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupDto.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupsProvider.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/ActivityGroupValueMatcher.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/EqualsValueMatcher.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/ModificationValueMatcher.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/NotNullValueMatcher.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/dtos/queryResults/ActivityGroupView.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/repository/activity/ActivityGroupRepository.kt diff --git a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectActivityController.kt b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectActivityController.kt index af74eacec4..ce8528831f 100644 --- a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectActivityController.kt +++ b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectActivityController.kt @@ -45,4 +45,18 @@ class ProjectActivityController( val views = activityService.getProjectActivity(projectId = projectHolder.project.id, pageable) return pagedResourcesAssembler.toModel(views, projectActivityModelAssembler) } + + @Operation( + summary = "Get project activity groups", + description = "This endpoints returns the activity grouped by time windows so it's easier to read on the frontend.", + ) + @GetMapping("/groups", produces = [MediaTypes.HAL_JSON_VALUE]) + @RequiresProjectPermissions([Scope.ACTIVITY_VIEW]) + @AllowApiAccess + fun getActivityGroups( + @ParameterObject pageable: Pageable, + ): PagedModel { + val views = activityService.getProjectActivity(projectId = projectHolder.project.id, pageable) + return pagedResourcesAssembler.toModel(views, projectActivityModelAssembler) + } } diff --git a/backend/app/build.gradle b/backend/app/build.gradle index 04733bba5c..d305e5c49e 100644 --- a/backend/app/build.gradle +++ b/backend/app/build.gradle @@ -100,7 +100,7 @@ dependencies { exclude group: 'io.netty', module: 'netty-codec-http' } testImplementation('io.netty:netty-codec-http:4.1.108.Final') - + testImplementation libs.springJooq /** * MISC diff --git a/backend/app/src/main/resources/application.yaml b/backend/app/src/main/resources/application.yaml index 4ab12cc349..6c401584ab 100644 --- a/backend/app/src/main/resources/application.yaml +++ b/backend/app/src/main/resources/application.yaml @@ -34,6 +34,8 @@ spring: initialize-schema: always datasource: auto-commit: false + jooq: + sql-dialect: postgres tolgee: authentication: enabled: false @@ -64,4 +66,6 @@ management: web: exposure: include: health,info,prometheus - +logging: + level: + org.jooq.Constants: off diff --git a/backend/app/src/test/kotlin/io/tolgee/activity/RootActivityProviderTest.kt b/backend/app/src/test/kotlin/io/tolgee/activity/RootActivityProviderTest.kt index 26d3e5a61b..94443bd329 100644 --- a/backend/app/src/test/kotlin/io/tolgee/activity/RootActivityProviderTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/activity/RootActivityProviderTest.kt @@ -10,7 +10,7 @@ import org.springframework.data.domain.Pageable class RootActivityProviderTest : ProjectAuthControllerTest("/v2/projects/") { @Test - fun `it applies the import`() { + fun `returns rooted activity`() { importData() val latestRevisionId = getLatestRevisionId() val items = diff --git a/backend/app/src/test/kotlin/io/tolgee/activity/groups/ActivityGroupsCreationTest.kt b/backend/app/src/test/kotlin/io/tolgee/activity/groups/ActivityGroupsCreationTest.kt new file mode 100644 index 0000000000..4d6f1764de --- /dev/null +++ b/backend/app/src/test/kotlin/io/tolgee/activity/groups/ActivityGroupsCreationTest.kt @@ -0,0 +1,231 @@ +package io.tolgee.activity.groups + +import com.posthog.java.PostHog +import io.tolgee.ProjectAuthControllerTest +import io.tolgee.batch.BatchJobService +import io.tolgee.development.testDataBuilder.data.BaseTestData +import io.tolgee.dtos.request.key.ComplexEditKeyDto +import io.tolgee.fixtures.andIsOk +import io.tolgee.model.activity.ActivityGroup +import io.tolgee.model.activity.ActivityModifiedEntity +import io.tolgee.model.activity.ActivityRevision +import io.tolgee.model.key.Key +import io.tolgee.model.translation.Translation +import io.tolgee.testing.annotations.ProjectJWTAuthTestMethod +import io.tolgee.testing.assert +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.mockito.Mockito +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.data.domain.Pageable +import java.time.Duration + +class ActivityGroupsCreationTest : ProjectAuthControllerTest("/v2/projects/") { + private lateinit var testData: BaseTestData + + @MockBean + @Autowired + lateinit var postHog: PostHog + + @Autowired + lateinit var batchJobService: BatchJobService + + @Autowired + lateinit var activityGroupService: ActivityGroupService + + @BeforeEach + fun setup() { + Mockito.reset(postHog) + } + + lateinit var key: Key + + private fun prepareTestData() { + testData = BaseTestData() + testData.user.name = "Franta" + testData.projectBuilder.apply { + addKey { + name = "key" + this@ActivityGroupsCreationTest.key = this + } + } + testDataService.saveTestData(testData.root) + projectSupplier = { testData.projectBuilder.self } + userAccount = testData.user + } + + @Test + @ProjectJWTAuthTestMethod + fun `it creates the groups in time windows`() { + prepareTestData() + assertItGroupsInTimeWindow() + assertItDoesNotGroupOutOfTimeWindow() + assertItStopsGroupingDueToAge() + } + + @Test + @ProjectJWTAuthTestMethod + fun `it creates correct groups per complex update`() { + prepareTestData() + performProjectAuthPut( + "keys/${key.id}/complex-update", + ComplexEditKeyDto( + name = "new name", + description = "Changed!", + tags = listOf("tag1", "tag2"), + translations = mapOf(testData.englishLanguage.tag to "Test"), + ), + ).andIsOk + + assertGroupsForActivity( + ActivityGroupType.KEY_NAME_EDIT, + ActivityGroupType.KEY_TAGS_EDIT, + ActivityGroupType.SET_TRANSLATIONS, + ) + + val groups = + activityGroupService.getProjectActivityGroups( + projectId = testData.project.id, + pageable = Pageable.ofSize(10), + ) + + groups + } + + private fun assertItStopsGroupingDueToAge() { + currentDateProvider.move(Duration.ofHours(3)) + + (1..23).forEach { + executeTranslationUpdate("Test $it") + currentDateProvider.move(Duration.ofHours(1)) + } + + assertGroupRevisionsCount(23) + + currentDateProvider.move(Duration.ofHours(2)) + executeTranslationUpdate("Test final") + assertGroupRevisionsCount(1) + } + + private fun assertGroupsForActivity(vararg types: ActivityGroupType) { + val activityRevision = findLastActivityRevision() + val groups = getActivityGroupsForRevision(activityRevision) + groups.map { it.type }.assert.containsExactlyInAnyOrder(*types) + } + + private fun assertItDoesNotGroupOutOfTimeWindow() { + // it's not the same group anymore + currentDateProvider.move(Duration.ofMinutes(123)) + + executeTranslationUpdate("Test 4") + assertGroupRevisionsCount(1) + assertLastGroupType(ActivityGroupType.SET_TRANSLATIONS) + assertLastValue("Test 4") + } + + private fun assertItGroupsInTimeWindow() { + executeTranslationUpdate("Test") + executeTranslationUpdate("Test 2") + + currentDateProvider.move(Duration.ofMinutes(65)) + // still the same group + executeTranslationUpdate("Test 3") + + asserGroupCount(1) + assertGroupRevisionsCount(3) + assertLastGroupType(ActivityGroupType.SET_TRANSLATIONS) + assertLastValue("Test 3") + } + + private fun assertGroupRevisionsCount(count: Int) { + executeInNewTransaction { + val activityRevision = findLastActivityRevision() + val groups = getActivityGroupsForRevision(activityRevision) + val group = groups.single() + entityManager.createQuery( + """ + select count(ar) from ActivityRevision ar + join ar.activityGroups ag + where ag.id = :groupId + """, + ) + .setParameter("groupId", group.id) + .singleResult + .assert.isEqualTo(count.toLong()) + } + } + + private fun asserGroupCount(count: Int) { + executeInNewTransaction { + val activityRevision = findLastActivityRevision() + val groups = getActivityGroupsForRevision(activityRevision) + groups.size.assert.isEqualTo(count) + } + } + + private fun assertLastGroupType(activityGroupType: ActivityGroupType) { + executeInNewTransaction { + val activityRevision = findLastActivityRevision() + val groups = getActivityGroupsForRevision(activityRevision) + groups.single().type.assert.isEqualTo(activityGroupType) + } + } + + private fun assertLastValue(value: String) { + executeInNewTransaction { + val activityRevision = findLastActivityRevision() + val groups = getActivityGroupsForRevision(activityRevision) + val group = groups.single() + val modifiedEntities = getModifiedEntitiesForGroup(group) + modifiedEntities.filter { it.entityClass == Translation::class.simpleName } + .last() + .modifications["text"]!! + .new.assert.isEqualTo(value) + } + } + + private fun executeTranslationUpdate(value: String) { + performProjectAuthPut( + "translations", + mapOf("key" to "key", "translations" to mapOf(testData.englishLanguage.tag to value)), + ).andIsOk + } + + private fun findLastActivityRevision(): ActivityRevision { + return entityManager.createQuery( + """ + select ar from ActivityRevision ar + order by ar.timestamp desc + limit 1 + """, + ActivityRevision::class.java, + ).singleResult + } + + private fun getActivityGroupsForRevision(activityRevision: ActivityRevision): MutableList { + return entityManager.createQuery( + """ + select ag from ActivityGroup ag + join fetch ag.activityRevisions ar + where ar.id = :activityRevisionId + """, + ActivityGroup::class.java, + ).setParameter("activityRevisionId", activityRevision.id) + .resultList + } + + private fun getModifiedEntitiesForGroup(group: ActivityGroup): MutableList { + return entityManager.createQuery( + """ + select ame from ActivityModifiedEntity ame + join fetch ame.activityRevision ar + join fetch ar.activityGroups ag + where ag.id = :groupId + order by ar.timestamp + """, + ActivityModifiedEntity::class.java, + ).setParameter("groupId", group.id) + .resultList + } +} diff --git a/backend/app/src/test/kotlin/io/tolgee/activity/openApi/ModificationSchemaGeneratorTest.kt b/backend/app/src/test/kotlin/io/tolgee/activity/openApi/ModificationSchemaGeneratorTest.kt index 75f67b1e2f..2fbebdba28 100644 --- a/backend/app/src/test/kotlin/io/tolgee/activity/openApi/ModificationSchemaGeneratorTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/activity/openApi/ModificationSchemaGeneratorTest.kt @@ -1,5 +1,6 @@ package io.tolgee.activity.openApi +import io.tolgee.activity.data.ActivityType import io.tolgee.configuration.openApi.activity.ModificationsSchemaGenerator import io.tolgee.model.key.Key import org.junit.jupiter.api.Test @@ -7,6 +8,10 @@ import org.junit.jupiter.api.Test class ModificationSchemaGeneratorTest { @Test fun `generates for key`() { - val schema = ModificationsSchemaGenerator().getModificationSchema(Key::class) + val schema = + ModificationsSchemaGenerator().getModificationSchema( + Key::class, + definition = ActivityType.CREATE_KEY.typeDefinitions!![Key::class]!!, + ) } } diff --git a/backend/app/src/test/resources/application.yaml b/backend/app/src/test/resources/application.yaml index e7970939a9..15dfd3b165 100644 --- a/backend/app/src/test/resources/application.yaml +++ b/backend/app/src/test/resources/application.yaml @@ -40,6 +40,8 @@ spring: enabled: false datasource: maximum-pool-size: 100 + jooq: + sql-dialect: postgres tolgee: postgres-autostart: enabled: true @@ -81,7 +83,6 @@ tolgee: server: http://localhost:8080 batch: concurrency: 10 - logging: level: io.tolgee.billing.api.v2.OrganizationInvoicesController: DEBUG @@ -91,4 +92,6 @@ logging: io.tolgee.component.CurrentDateProvider: DEBUG io.tolgee.component.reporting.BusinessEventPublisher: DEBUG io.tolgee.ExceptionHandlers: DEBUG - io.tolgee.component.reporting.ReportingService: DEBUG \ No newline at end of file + io.tolgee.component.reporting.ReportingService: DEBUG + org.jooq.tools.LoggerListener: DEBUG + org.jooq.Constants: off diff --git a/backend/data/build.gradle b/backend/data/build.gradle index ee98b04a36..d67b4e0bc7 100644 --- a/backend/data/build.gradle +++ b/backend/data/build.gradle @@ -98,6 +98,7 @@ dependencies { implementation "org.springframework.boot:spring-boot-configuration-processor" implementation "org.springframework.boot:spring-boot-starter-batch" implementation "org.springframework.boot:spring-boot-starter-websocket" + implementation libs.springJooq /** * DB diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupDto.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupDto.kt new file mode 100644 index 0000000000..23227a593d --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupDto.kt @@ -0,0 +1,10 @@ +package io.tolgee.activity.groups + +import java.util.* + +data class ActivityGroupDto( + val id: Long, + val activityGroupType: ActivityGroupType, + val latestTimestamp: Date, + val earliestTimestamp: Date, +) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupService.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupService.kt index 8a7b6dc376..c3ba137b55 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupService.kt @@ -1,13 +1,25 @@ package io.tolgee.activity.groups import io.tolgee.activity.ModifiedEntitiesType +import io.tolgee.component.CurrentDateProvider +import io.tolgee.dtos.queryResults.ActivityGroupView +import io.tolgee.model.activity.ActivityGroup import io.tolgee.model.activity.ActivityRevision +import io.tolgee.repository.activity.ActivityGroupRepository +import org.jooq.DSLContext import org.springframework.context.ApplicationContext +import org.springframework.data.domain.PageImpl +import org.springframework.data.domain.Pageable import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.util.* @Service class ActivityGroupService( private val applicationContext: ApplicationContext, + private val activityGroupRepository: ActivityGroupRepository, + private val currentDateProvider: CurrentDateProvider, + private val jooqContext: DSLContext, ) { fun addToGroup( activityRevision: ActivityRevision, @@ -15,4 +27,103 @@ class ActivityGroupService( ) { ActivityGrouper(activityRevision, modifiedEntities, applicationContext).addToGroup() } + + fun getOrCreateCurrentActivityGroupDtos( + type: ActivityGroupType, + projectId: Long?, + authorId: Long?, + ): ActivityGroupDto { + val existing = findSuitableExistingSuitableGroupDto(type, projectId, authorId) + return existing ?: createActivityGroupDto(type, projectId, authorId) + } + + private fun createActivityGroupDto( + type: ActivityGroupType, + projectId: Long?, + authorId: Long?, + ): ActivityGroupDto { + val entity = createActivityGroup(type, projectId, authorId) + return ActivityGroupDto( + entity.id, + entity.type, + currentDateProvider.date, + currentDateProvider.date, + ) + } + + private fun createActivityGroup( + type: ActivityGroupType, + projectId: Long?, + authorId: Long?, + ): ActivityGroup { + return ActivityGroup( + type = type, + ).also { + it.authorId = authorId + it.projectId = projectId + activityGroupRepository.saveAndFlush(it) + } + } + + private fun findSuitableExistingSuitableGroupDto( + type: ActivityGroupType, + projectId: Long?, + authorId: Long?, + ): ActivityGroupDto? { + val latest = findLatest(type, authorId, projectId) ?: return null + if (latest.isTooOld || latest.lastActivityTooEarly) { + return null + } + return latest + } + + private fun findLatest( + type: ActivityGroupType, + authorId: Long?, + projectId: Long?, + ): ActivityGroupDto? { + val result = + activityGroupRepository.findLatest( + groupTypeName = type.name, + authorId = authorId, + projectId = projectId, + ) + + if (result.isEmpty()) { + return null + } + + val single = result.single() + + return ActivityGroupDto( + single[0] as Long, + ActivityGroupType.valueOf(single[1] as String), + // if the group is empty we can just consider it as created now + single[2] as Date? ?: currentDateProvider.date, + single[3] as Date? ?: currentDateProvider.date, + ) + } + + @Transactional + fun getProjectActivityGroups( + projectId: Long, + pageable: Pageable, + ): PageImpl { + return ActivityGroupsProvider(projectId, pageable, applicationContext).get() + } + + private val ActivityGroupDto.isTooOld: Boolean + get() { + return this.earliestTimestamp.time + GROUP_MAX_AGE < currentDateProvider.date.time + } + + private val ActivityGroupDto.lastActivityTooEarly: Boolean + get() { + return latestTimestamp.time + GROUP_MAX_LAST_ACTIVITY_AGE < currentDateProvider.date.time + } + + companion object { + const val GROUP_MAX_AGE = 1000 * 60 * 60 * 24 + const val GROUP_MAX_LAST_ACTIVITY_AGE = 1000 * 60 * 60 * 2 + } } diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupType.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupType.kt index 69843f2306..73ba922d3e 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupType.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupType.kt @@ -2,6 +2,9 @@ package io.tolgee.activity.groups import io.tolgee.activity.data.ActivityType import io.tolgee.activity.data.RevisionType +import io.tolgee.activity.groups.matchers.ActivityGroupValueMatcher.Companion.eq +import io.tolgee.activity.groups.matchers.ActivityGroupValueMatcher.Companion.modification +import io.tolgee.activity.groups.matchers.ActivityGroupValueMatcher.Companion.notNull import io.tolgee.model.Language import io.tolgee.model.Project import io.tolgee.model.Screenshot @@ -19,7 +22,7 @@ import io.tolgee.model.webhook.WebhookConfig enum class ActivityGroupType( val sourceActivityTypes: List, - val allowedGroupEntityModificationDefinitions: List>, + val modifications: List>, ) { SET_TRANSLATION_STATE( listOf(ActivityType.SET_TRANSLATION_STATE, ActivityType.COMPLEX_EDIT), @@ -28,6 +31,12 @@ enum class ActivityGroupType( entityClass = Translation::class, revisionTypes = listOf(RevisionType.MOD), modificationProps = listOf(Translation::state, Translation::outdated, Translation::mtProvider), + deniedValues = + mapOf( + Translation::state to TranslationState.REVIEWED, + Translation::text to modification(eq(null) to notNull()), + ), + countInView = true, ), ), ), @@ -40,6 +49,7 @@ enum class ActivityGroupType( revisionTypes = listOf(RevisionType.MOD), modificationProps = listOf(Translation::state, Translation::outdated, Translation::mtProvider), allowedValues = mapOf(Translation::state to TranslationState.REVIEWED), + countInView = true, ), ), ), @@ -50,6 +60,8 @@ enum class ActivityGroupType( GroupEntityModificationDefinition( entityClass = Translation::class, revisionTypes = listOf(RevisionType.ADD, RevisionType.DEL, RevisionType.MOD), + modificationProps = listOf(Translation::text), + countInView = true, ), ), ), @@ -62,6 +74,7 @@ enum class ActivityGroupType( revisionTypes = listOf(RevisionType.MOD), modificationProps = listOf(Translation::auto, Translation::mtProvider), allowedValues = mapOf(Translation::mtProvider to null, Translation::auto to false), + countInView = true, ), ), ), @@ -73,6 +86,7 @@ enum class ActivityGroupType( entityClass = Translation::class, revisionTypes = listOf(RevisionType.MOD), modificationProps = listOf(Translation::outdated), + countInView = true, ), ), ), @@ -83,6 +97,7 @@ enum class ActivityGroupType( GroupEntityModificationDefinition( entityClass = TranslationComment::class, revisionTypes = listOf(RevisionType.ADD), + countInView = true, ), GroupEntityModificationDefinition( entityClass = Translation::class, @@ -97,6 +112,7 @@ enum class ActivityGroupType( GroupEntityModificationDefinition( entityClass = TranslationComment::class, revisionTypes = listOf(RevisionType.DEL), + countInView = true, ), ), ), @@ -108,6 +124,7 @@ enum class ActivityGroupType( entityClass = TranslationComment::class, revisionTypes = listOf(RevisionType.MOD), modificationProps = listOf(TranslationComment::text), + countInView = true, ), ), ), @@ -119,6 +136,7 @@ enum class ActivityGroupType( entityClass = TranslationComment::class, revisionTypes = listOf(RevisionType.MOD), modificationProps = listOf(TranslationComment::state), + countInView = true, ), ), ), @@ -129,6 +147,7 @@ enum class ActivityGroupType( GroupEntityModificationDefinition( entityClass = Screenshot::class, revisionTypes = listOf(RevisionType.DEL), + countInView = true, ), GroupEntityModificationDefinition( entityClass = KeyScreenshotReference::class, @@ -143,6 +162,7 @@ enum class ActivityGroupType( GroupEntityModificationDefinition( entityClass = Screenshot::class, revisionTypes = listOf(RevisionType.ADD), + countInView = true, ), GroupEntityModificationDefinition( entityClass = KeyScreenshotReference::class, @@ -163,10 +183,12 @@ enum class ActivityGroupType( entityClass = KeyMeta::class, revisionTypes = listOf(RevisionType.MOD), modificationProps = listOf(KeyMeta::tags), + countInView = true, ), GroupEntityModificationDefinition( entityClass = Tag::class, revisionTypes = listOf(RevisionType.ADD, RevisionType.DEL), + countInView = true, ), ), ), @@ -178,10 +200,12 @@ enum class ActivityGroupType( entityClass = Key::class, revisionTypes = listOf(RevisionType.MOD), modificationProps = listOf(Key::name, Key::namespace), + countInView = true, ), GroupEntityModificationDefinition( entityClass = Namespace::class, revisionTypes = listOf(RevisionType.ADD, RevisionType.DEL), + countInView = true, ), ), ), @@ -192,6 +216,7 @@ enum class ActivityGroupType( GroupEntityModificationDefinition( entityClass = Key::class, revisionTypes = listOf(RevisionType.DEL), + countInView = true, ), ), ), @@ -202,6 +227,7 @@ enum class ActivityGroupType( GroupEntityModificationDefinition( entityClass = Key::class, revisionTypes = listOf(RevisionType.ADD), + countInView = true, ), GroupEntityModificationDefinition( entityClass = KeyMeta::class, @@ -216,6 +242,7 @@ enum class ActivityGroupType( GroupEntityModificationDefinition( entityClass = Key::class, revisionTypes = listOf(RevisionType.ADD), + countInView = true, ), GroupEntityModificationDefinition( entityClass = KeyMeta::class, @@ -225,6 +252,7 @@ enum class ActivityGroupType( GroupEntityModificationDefinition( entityClass = Translation::class, revisionTypes = listOf(RevisionType.ADD), + countInView = true, ), GroupEntityModificationDefinition( entityClass = Namespace::class, @@ -239,6 +267,7 @@ enum class ActivityGroupType( GroupEntityModificationDefinition( entityClass = Language::class, revisionTypes = listOf(RevisionType.ADD), + countInView = true, ), ), ), @@ -250,6 +279,7 @@ enum class ActivityGroupType( entityClass = Language::class, revisionTypes = listOf(RevisionType.MOD), modificationProps = listOf(Language::name, Language::tag, Language::originalName, Language::flagEmoji), + countInView = true, ), ), ), @@ -260,6 +290,7 @@ enum class ActivityGroupType( GroupEntityModificationDefinition( entityClass = Language::class, revisionTypes = listOf(RevisionType.DEL), + countInView = true, ), ), ), @@ -270,6 +301,7 @@ enum class ActivityGroupType( GroupEntityModificationDefinition( entityClass = Project::class, revisionTypes = listOf(RevisionType.ADD), + countInView = true, ), ), ), @@ -299,6 +331,7 @@ enum class ActivityGroupType( entityClass = Namespace::class, revisionTypes = listOf(RevisionType.MOD), modificationProps = listOf(Namespace::name), + countInView = true, ), ), ), @@ -310,6 +343,7 @@ enum class ActivityGroupType( entityClass = Translation::class, revisionTypes = listOf(RevisionType.MOD, RevisionType.ADD), modificationProps = listOf(Translation::state, Translation::text, Translation::outdated, Translation::auto), + countInView = true, ), ), ), @@ -321,6 +355,7 @@ enum class ActivityGroupType( entityClass = Translation::class, revisionTypes = listOf(RevisionType.MOD, RevisionType.ADD), modificationProps = listOf(Translation::state, Translation::text, Translation::outdated, Translation::auto), + countInView = true, ), ), ), @@ -332,6 +367,7 @@ enum class ActivityGroupType( entityClass = Translation::class, revisionTypes = listOf(RevisionType.MOD, RevisionType.ADD), modificationProps = listOf(Translation::state, Translation::text, Translation::outdated, Translation::auto), + countInView = true, ), ), ), @@ -350,6 +386,7 @@ enum class ActivityGroupType( Translation::outdated to false, Translation::auto to false, ), + countInView = true, ), ), ), @@ -361,6 +398,7 @@ enum class ActivityGroupType( entityClass = Translation::class, revisionTypes = listOf(RevisionType.MOD, RevisionType.ADD), modificationProps = listOf(Translation::state, Translation::text, Translation::outdated, Translation::auto), + countInView = true, ), ), ), @@ -372,6 +410,7 @@ enum class ActivityGroupType( entityClass = Translation::class, revisionTypes = listOf(RevisionType.MOD), modificationProps = listOf(Translation::state, Translation::outdated, Translation::auto), + countInView = true, ), ), ), diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGrouper.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGrouper.kt index 98ac011882..4558952018 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGrouper.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGrouper.kt @@ -1,21 +1,51 @@ package io.tolgee.activity.groups import io.tolgee.activity.ModifiedEntitiesType +import io.tolgee.activity.data.PropertyModification +import io.tolgee.activity.groups.matchers.ActivityGroupValueMatcher +import io.tolgee.model.EntityWithId +import io.tolgee.model.activity.ActivityModifiedEntity import io.tolgee.model.activity.ActivityRevision +import jakarta.persistence.EntityManager import org.springframework.context.ApplicationContext +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 class ActivityGrouper( - activityRevision: ActivityRevision, - modifiedEntities: ModifiedEntitiesType, - applicationContext: ApplicationContext, + private val activityRevision: ActivityRevision, + private val modifiedEntities: ModifiedEntitiesType, + private val applicationContext: ApplicationContext, ) { fun addToGroup() { + val groupTypes = findGroupTypes() + groupTypes.forEach { + val groupIdToAddTo = getActivityGroupIds(it) + addToGroup(groupIdToAddTo) + } + } + + private fun addToGroup(groupId: Long) { + entityManager.createNativeQuery( + """ + insert into activity_revision_activity_groups (activity_revisions_id, activity_groups_id) + values (:activityRevisionId, :activityGroupId) + """, + ) + .setParameter("activityRevisionId", activityRevision.id) + .setParameter("activityGroupId", groupId) + .executeUpdate() } - fun findGroupTypes() { - val type = type ?: return + private fun getActivityGroupIds(type: ActivityGroupType): Long { + return activityGroupService.getOrCreateCurrentActivityGroupDtos( + type, + activityRevision.projectId, + activityRevision.authorId, + ).id + } - ActivityGroupType.values().filter { it.matches } + private fun findGroupTypes(): List { + return ActivityGroupType.entries.filter { it.matches } } private val ActivityGroupType.matches: Boolean @@ -23,7 +53,70 @@ class ActivityGrouper( if (!this.sourceActivityTypes.contains(type)) { return false } + + return modifiedEntities.any { modifiedEntity -> + this.modifications.any { definition -> + definition.matchesModifiedEntity(modifiedEntity) + } + } + } + + private fun GroupEntityModificationDefinition<*>.matchesModifiedEntity(entityEntry: ModifiedEntityType): Boolean { + if (entityEntry.key != entityClass) { + return false + } + + val isAnyWithAllowedType = entityEntry.value.any { it.value.revisionType in revisionTypes } + if (!isAnyWithAllowedType) { + return false + } + + val anyWithModifiedColumn = + entityEntry.value.values.any { entity -> + entity.modifications.any { modification -> + modificationProps?.any { it.name == modification.key } ?: true + } + } + + if (!anyWithModifiedColumn) { + return false + } + + if (!allowedValues.matchesEntityModification(entityEntry)) { + return false + } + + val isDenied = deniedValues?.matchesEntityModification(entityEntry) ?: false + return !isDenied + } + + private fun Map, Any?>?.matchesEntityModification(entry: ModifiedEntityType): Boolean { + return entry.value.values.any { entity -> + entity.modifications.any { modification -> + this?.all { compareValue(it.value, modification.value) && it.key.name == modification.key } ?: true + } } + } + + private fun compareValue( + value: Any?, + value1: PropertyModification, + ): Boolean { + return when (value) { + is ActivityGroupValueMatcher -> value.match(value1.new) + else -> value == value1.new + } + } private val type = activityRevision.type + + private val activityGroupService by lazy { + applicationContext.getBean(ActivityGroupService::class.java) + } + + private val entityManager: EntityManager by lazy { + applicationContext.getBean(EntityManager::class.java) + } } + +private typealias ModifiedEntityType = Map.Entry, MutableMap> diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupsProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupsProvider.kt new file mode 100644 index 0000000000..ffa16bae17 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupsProvider.kt @@ -0,0 +1,144 @@ +package io.tolgee.activity.groups + +import io.tolgee.activity.groups.matchers.ActivityGroupValueMatcher +import io.tolgee.activity.groups.matchers.EqualsValueMatcher +import io.tolgee.dtos.queryResults.ActivityGroupView +import org.jooq.Condition +import org.jooq.DSLContext +import org.jooq.Field +import org.jooq.JSON +import org.jooq.impl.DSL +import org.jooq.impl.DSL.field +import org.jooq.impl.DSL.max +import org.jooq.impl.DSL.table +import org.springframework.context.ApplicationContext +import org.springframework.data.domain.PageImpl +import org.springframework.data.domain.Pageable +import java.util.* + +class ActivityGroupsProvider(val projectId: Long, val pageable: Pageable, applicationContext: ApplicationContext) { + fun get(): PageImpl { + page.forEach { + val counts = counts[it.id] ?: emptyMap() + it.counts = counts + } + + return page + } + + private val page by lazy { + val from = table("activity_group").`as`("ag") + val where = field("ag.project_id").eq(projectId) + + val count = jooqContext.selectCount().from(from).where(where).fetchOne(0, Long::class.java)!! + + val result = + jooqContext.select( + field("ag.id"), + field("ag.type"), + field("ag.author_id"), + max(field("ar.timestamp")), + ) + .from(from) + .leftJoin(table("activity_revision_activity_groups").`as`("arag")) + .on(field("ag.id").eq(field("arag.activity_groups_id"))) + .leftJoin(table("activity_revision").`as`("ar")) + .on(field("ar.id").eq(field("arag.activity_revisions_id"))) + .where(where) + .groupBy(field("ag.id")) + .orderBy(max(field("ar.timestamp")).desc()) + .limit(pageable.pageSize) + .offset(pageable.offset).fetch().map { + ActivityGroupView( + it[0] as Long, + ActivityGroupType.valueOf(it[1] as String), + it[3] as Date, + ) + } + + PageImpl(result, pageable, count) + } + + private val counts by lazy { + val byType = page.groupBy { it.type } + byType.flatMap { (type, items) -> + getCounts(type, items).map { it.key to it.value } + }.toMap() + } + + private fun getModificationCondition(definition: GroupEntityModificationDefinition<*>): Condition { + return field("ame.entity_class").eq(definition.entityClass.simpleName) + .and(field("ame.revision_type").`in`(definition.revisionTypes.map { it.ordinal })) + .also { + if (definition.modificationProps != null) { + it.and("array(select jsonb_object_keys(ame.modifications)) && ${allowedModString(definition)}") + } + }.also { + it.and(getAllowedValuesCondition(definition)) + } + .also { + it.and(getDeniedValuesCondition(definition)) + } + } + + private fun getAllowedValuesCondition(definition: GroupEntityModificationDefinition<*>): Condition { + val allowedValues = definition.allowedValues ?: return DSL.noCondition() + val conditions = getValueMatcherConditions(allowedValues) + return DSL.and(conditions) + } + + private fun getDeniedValuesCondition(definition: GroupEntityModificationDefinition<*>): Condition { + val allowedValues = definition.allowedValues ?: return DSL.noCondition() + val conditions = getValueMatcherConditions(allowedValues) + return DSL.not(DSL.or(conditions)) + } + + private fun getValueMatcherConditions(values: Map): List { + return values.map { + val matcher = + when (val requiredValue = it.value) { + is ActivityGroupValueMatcher -> requiredValue + else -> EqualsValueMatcher(requiredValue) + } + + @Suppress("UNCHECKED_CAST") + matcher.createRootSqlCondition(field("ame.modifications") as Field) + } + } + + private fun allowedModString(definition: GroupEntityModificationDefinition<*>): String { + return "{${definition.modificationProps?.joinToString(",")}}" + } + + private fun getCounts( + type: ActivityGroupType, + items: List, + ): MutableMap> { + val groupIds = items.map { it.id } + val result = mutableMapOf>() + type.modifications + .filter { it.countInView } + .forEach { definition -> + val queryResult = + jooqContext + .select(field("arag.activity_groups_id"), DSL.count()) + .from(table("activity_modified_entity").`as`("ame")) + .join(table("activity_revision").`as`("ar")) + .on(field("ar.id").eq(field("ame.activity_revision_id"))) + .join(table("activity_revision_activity_groups").`as`("arag")) + .on(field("ar.id").eq(field("arag.activity_revisions_id"))) + .where(field("arag.activity_groups_id").`in`(groupIds).and(getModificationCondition(definition))) + .groupBy(field("arag.activity_groups_id")).fetch() + queryResult.forEach { + val groupMap = + result.computeIfAbsent(it[0] as Long) { + mutableMapOf() + } + groupMap[definition.entityClass.simpleName!!] = it[1] as Int + } + } + return result + } + + private val jooqContext = applicationContext.getBean(DSLContext::class.java) +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/GroupEntityModificationDefinition.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/GroupEntityModificationDefinition.kt index 5b151533ee..89d267f2d9 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/GroupEntityModificationDefinition.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/GroupEntityModificationDefinition.kt @@ -9,4 +9,6 @@ class GroupEntityModificationDefinition( val revisionTypes: List, val modificationProps: List>? = null, val allowedValues: Map, Any?>? = null, + val deniedValues: Map, Any?>? = null, + val countInView: Boolean = false, ) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/ActivityGroupValueMatcher.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/ActivityGroupValueMatcher.kt new file mode 100644 index 0000000000..9fafd88c6c --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/ActivityGroupValueMatcher.kt @@ -0,0 +1,22 @@ +package io.tolgee.activity.groups.matchers + +import org.jooq.Condition +import org.jooq.Field +import org.jooq.JSON + +interface ActivityGroupValueMatcher { + fun match(value: Any?): Boolean + + fun createChildSqlCondition(field: Field): Condition + + fun createRootSqlCondition(field: Field): Condition + + companion object { + fun notNull() = NotNullValueMatcher() + + fun modification(pair: Pair) = + ModificationValueMatcher(pair.first, pair.second) + + fun eq(value: Any?) = EqualsValueMatcher(value) + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/EqualsValueMatcher.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/EqualsValueMatcher.kt new file mode 100644 index 0000000000..113cdc148c --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/EqualsValueMatcher.kt @@ -0,0 +1,30 @@ +package io.tolgee.activity.groups.matchers + +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import io.tolgee.activity.data.PropertyModification +import org.jooq.Condition +import org.jooq.Field +import org.jooq.JSON +import org.jooq.impl.DSL + +class EqualsValueMatcher(val value: Any?) : ActivityGroupValueMatcher { + override fun match(value: Any?): Boolean { + if (value is PropertyModification) { + return value.new == this.value + } + return this.value == value + } + + override fun createChildSqlCondition(field: Field): Condition { + return field.eq(jsonValue) + } + + override fun createRootSqlCondition(field: Field): Condition { + val new = DSL.jsonGetAttribute(field, "new") + return createChildSqlCondition(new) + } + + private val jsonValue by lazy { + JSON.json(jacksonObjectMapper().writeValueAsString(value)) + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/ModificationValueMatcher.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/ModificationValueMatcher.kt new file mode 100644 index 0000000000..4f000d97a1 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/ModificationValueMatcher.kt @@ -0,0 +1,29 @@ +package io.tolgee.activity.groups.matchers + +import io.tolgee.activity.data.PropertyModification +import org.jooq.Condition +import org.jooq.Field +import org.jooq.JSON +import org.jooq.impl.DSL + +class ModificationValueMatcher( + val old: ActivityGroupValueMatcher, + val new: ActivityGroupValueMatcher, +) : ActivityGroupValueMatcher { + override fun match(value: Any?): Boolean { + if (value is PropertyModification) { + return old.match(value.old) && new.match(value.new) + } + throw IllegalArgumentException("Value is not PropertyModification") + } + + override fun createChildSqlCondition(field: Field): Condition { + throw UnsupportedOperationException("ModificationValueMatcher cannot be used as child condition") + } + + override fun createRootSqlCondition(field: Field): Condition { + val oldField = DSL.jsonGetAttribute(field, "old") + val newField = DSL.jsonGetAttribute(field, "new") + return old.createChildSqlCondition(oldField).and(new.createChildSqlCondition(newField)) + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/NotNullValueMatcher.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/NotNullValueMatcher.kt new file mode 100644 index 0000000000..a49900fbf3 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/NotNullValueMatcher.kt @@ -0,0 +1,25 @@ +package io.tolgee.activity.groups.matchers + +import io.tolgee.activity.data.PropertyModification +import org.jooq.Condition +import org.jooq.Field +import org.jooq.JSON +import org.jooq.impl.DSL + +class NotNullValueMatcher : ActivityGroupValueMatcher { + override fun match(value: Any?): Boolean { + if (value is PropertyModification) { + return value.new != null + } + return value != null + } + + override fun createChildSqlCondition(field: Field): Condition { + return field.isNotNull + } + + override fun createRootSqlCondition(field: Field): Condition { + val new = DSL.jsonGetAttribute(field, "new") + return createChildSqlCondition(new) + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/dtos/queryResults/ActivityGroupView.kt b/backend/data/src/main/kotlin/io/tolgee/dtos/queryResults/ActivityGroupView.kt new file mode 100644 index 0000000000..2a57ab84dc --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/dtos/queryResults/ActivityGroupView.kt @@ -0,0 +1,13 @@ +package io.tolgee.dtos.queryResults + +import io.tolgee.activity.groups.ActivityGroupType + +data class ActivityGroupView( + val id: Long, + val type: ActivityGroupType, + val timestamp: java.util.Date, + /** + * Counts of items in this group by entity class name + */ + var counts: Map? = null, +) diff --git a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityGroup.kt b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityGroup.kt index 9bc800e98a..f8f873b922 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityGroup.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityGroup.kt @@ -1,43 +1,20 @@ package io.tolgee.model.activity -import io.hypersistence.utils.hibernate.type.json.JsonBinaryType -import io.tolgee.activity.data.ActivityType -import io.tolgee.component.CurrentDateProvider -import io.tolgee.model.batch.BatchJob -import io.tolgee.model.batch.BatchJobChunkExecution -import jakarta.persistence.Column +import io.tolgee.activity.groups.ActivityGroupType import jakarta.persistence.Entity -import jakarta.persistence.EntityListeners import jakarta.persistence.EnumType import jakarta.persistence.Enumerated -import jakarta.persistence.FetchType import jakarta.persistence.GeneratedValue import jakarta.persistence.GenerationType import jakarta.persistence.Id -import jakarta.persistence.Index -import jakarta.persistence.OneToMany -import jakarta.persistence.OneToOne -import jakarta.persistence.PrePersist +import jakarta.persistence.ManyToMany import jakarta.persistence.SequenceGenerator -import jakarta.persistence.Table -import jakarta.persistence.Temporal -import jakarta.persistence.TemporalType -import org.hibernate.annotations.Type -import org.springframework.beans.factory.ObjectFactory -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.beans.factory.annotation.Configurable -import java.util.* @Entity -@Table( - indexes = [ - Index(columnList = "projectId"), - Index(columnList = "authorId"), - Index(columnList = "type"), - ], -) -@EntityListeners(ActivityGroup.Companion.ActivityRevisionListener::class) -class ActivityGroup : java.io.Serializable { +class ActivityGroup( + @Enumerated(EnumType.STRING) + var type: ActivityGroupType, +) { @Id @SequenceGenerator( name = "activitySequenceGenerator", @@ -51,69 +28,16 @@ class ActivityGroup : java.io.Serializable { ) val id: Long = 0 - @Temporal(TemporalType.TIMESTAMP) - @Column(name = "timestamp", nullable = false, updatable = false) - lateinit var timestamp: Date - /** * We don't want a foreign key, since user could have been deleted */ var authorId: Long? = null - @Column(columnDefinition = "jsonb") - @Type(JsonBinaryType::class) - var meta: MutableMap? = null - - @Enumerated(EnumType.STRING) - var type: ActivityType? = null - /** * Project of the change */ var projectId: Long? = null - @OneToMany(mappedBy = "activityRevision") - var describingRelations: MutableList = mutableListOf() - - @OneToMany(mappedBy = "activityRevision") - var modifiedEntities: MutableList = mutableListOf() - - /** - * For chunked jobs, this field is set for every chunk. - * When job is running, each chunk has it's own activity revision. - * When job is finished, all the chunks revisions are merged into one revision and - * this field is set to null. - * - * Instead, [batchJob] is set. - */ - @OneToOne(fetch = FetchType.LAZY) - var batchJobChunkExecution: BatchJobChunkExecution? = null - - @OneToOne(fetch = FetchType.LAZY) - var batchJob: BatchJob? = null - - /** - * The instance is created in the Holder by default, but it is not initialized by the interceptor, - * so projectId and authorId might be null. - * - * This flag is set to true when the instance is initialized by the interceptor. - */ - @Transient - var isInitializedByInterceptor: Boolean = false - - @Transient - var cancelledBatchJobExecutionCount: Int? = null - - companion object { - @Configurable - class ActivityRevisionListener { - @Autowired - lateinit var provider: ObjectFactory - - @PrePersist - fun preRemove(activityRevision: ActivityGroup) { - activityRevision.timestamp = provider.`object`.date - } - } - } + @ManyToMany(mappedBy = "activityGroups") + var activityRevisions: MutableList = mutableListOf() } diff --git a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityRevision.kt b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityRevision.kt index ff81687338..c746520916 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityRevision.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityRevision.kt @@ -15,6 +15,7 @@ import jakarta.persistence.GeneratedValue import jakarta.persistence.GenerationType import jakarta.persistence.Id import jakarta.persistence.Index +import jakarta.persistence.ManyToMany import jakarta.persistence.OneToMany import jakarta.persistence.OneToOne import jakarta.persistence.PrePersist @@ -34,6 +35,7 @@ import java.util.* Index(columnList = "projectId"), Index(columnList = "authorId"), Index(columnList = "type"), + Index(columnList = "timestamp"), ], ) @EntityListeners(ActivityRevision.Companion.ActivityRevisionListener::class) @@ -104,6 +106,9 @@ class ActivityRevision : java.io.Serializable { @Transient var cancelledBatchJobExecutionCount: Int? = null + @ManyToMany + var activityGroups: MutableList = mutableListOf() + companion object { @Configurable class ActivityRevisionListener { diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/activity/ActivityGroupRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/activity/ActivityGroupRepository.kt new file mode 100644 index 0000000000..2990549609 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/repository/activity/ActivityGroupRepository.kt @@ -0,0 +1,35 @@ +package io.tolgee.repository.activity + +import io.tolgee.model.activity.ActivityGroup +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.stereotype.Repository + +@Repository +interface ActivityGroupRepository : JpaRepository { + @Query( + nativeQuery = true, + value = """ + SELECT + ag.id, + ag.type, + MAX(ar.timestamp) AS last_activity, + MIN(ar.timestamp) AS first_activity + FROM activity_group ag + left JOIN activity_revision_activity_groups arag ON arag.activity_groups_id = ag.id + left JOIN activity_revision ar ON ar.id = arag.activity_revisions_id + WHERE + ag.project_id = :projectId + AND ag.author_id = :authorId + AND ag.type = :groupTypeName + GROUP BY ag.id + order by ag.id desc + limit 1 + """, + ) + fun findLatest( + groupTypeName: String, + authorId: Long?, + projectId: Long?, + ): List> +} diff --git a/backend/data/src/main/resources/db/changelog/schema.xml b/backend/data/src/main/resources/db/changelog/schema.xml index c997527883..461f16f9a7 100644 --- a/backend/data/src/main/resources/db/changelog/schema.xml +++ b/backend/data/src/main/resources/db/changelog/schema.xml @@ -3311,4 +3311,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ee/backend/tests/src/test/resources/application.yaml b/ee/backend/tests/src/test/resources/application.yaml index 620f98ae53..caa22df84f 100644 --- a/ee/backend/tests/src/test/resources/application.yaml +++ b/ee/backend/tests/src/test/resources/application.yaml @@ -83,9 +83,9 @@ springdoc: api-docs: enabled: false -#logging: -# level: +logging: + level: # org.springframework.orm.jpa: DEBUG # org.springframework.transaction: DEBUG # org.hibernate.type: TRACE - + org.jooq.Constants: off diff --git a/settings.gradle b/settings.gradle index 9bcde28d03..e6273981a6 100644 --- a/settings.gradle +++ b/settings.gradle @@ -71,6 +71,7 @@ dependencyResolutionManagement { library('mailjet', "com.mailjet:mailjet-client:5.2.5") library('azureBlob', 'com.azure.spring:spring-cloud-azure-starter-storage-blob:5.11.0') library('commonsText', 'org.apache.commons:commons-text:1.10.0') + library('springJooq', "org.springframework.boot:spring-boot-starter-jooq:3.3.0") } } } From 3a8d10c01359ca10b025bf5296caff2bc373e65b Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Wed, 31 Jul 2024 18:05:38 +0200 Subject: [PATCH 39/44] feat: Project creation group backend --- .../controllers/ProjectActivityController.kt | 13 +- .../hateoas/activity/ActivityGroupModel.kt | 18 + .../activity/ActivityGroupModelAssembler.kt | 29 + .../tolgee/hateoas/language/LanguageModel.kt | 13 +- .../userAccount/SimpleUserAccountModel.kt | 2 +- .../SimpleUserAccountModelAssembler.kt | 7 +- .../groups/ProjectCreationGroupViewTest.kt | 107 + .../io/tolgee/activity/ActivityHolder.kt | 3 +- .../io/tolgee/activity/ActivityService.kt | 22 +- .../activity/groups/ActivityGroupService.kt | 2 +- .../activity/groups/ActivityGroupType.kt | 4 + .../tolgee/activity/groups/ActivityGrouper.kt | 9 +- .../activity/groups/ActivityGroupsProvider.kt | 36 +- .../activity/groups/GroupModelProvider.kt | 5 + .../createProject/CreateProjectGroupModel.kt | 8 + .../CreateProjectGroupModelProvider.kt | 58 + .../createProject/LanguageModel.kt | 11 + .../iterceptor/InterceptedEventsManager.kt | 11 +- .../kotlin/io/tolgee/api/ILanguageModel.kt | 9 + .../kotlin/io/tolgee/api/SimpleUserAccount.kt | 9 + .../dtos/queryResults/ActivityGroupView.kt | 5 +- .../queryResults/TranslationHistoryView.kt | 2 +- .../kotlin/io/tolgee/model/UserAccount.kt | 10 +- webapp/package.json | 42 +- webapp/src/component/RootRouter.tsx | 2 - .../common/avatar/useAutoAvatarImgSrc.tsx | 69 +- webapp/src/service/apiSchema.generated.ts | 2857 +++++++++++++++-- 27 files changed, 2889 insertions(+), 474 deletions(-) create mode 100644 backend/api/src/main/kotlin/io/tolgee/hateoas/activity/ActivityGroupModel.kt create mode 100644 backend/api/src/main/kotlin/io/tolgee/hateoas/activity/ActivityGroupModelAssembler.kt create mode 100644 backend/app/src/test/kotlin/io/tolgee/activity/groups/ProjectCreationGroupViewTest.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/GroupModelProvider.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/CreateProjectGroupModel.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/CreateProjectGroupModelProvider.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/LanguageModel.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/api/ILanguageModel.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/api/SimpleUserAccount.kt diff --git a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectActivityController.kt b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectActivityController.kt index c32f33ec13..f1fcf04b29 100644 --- a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectActivityController.kt +++ b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectActivityController.kt @@ -9,7 +9,11 @@ import io.swagger.v3.oas.annotations.Parameter import io.swagger.v3.oas.annotations.media.ExampleObject import io.swagger.v3.oas.annotations.tags.Tag import io.tolgee.activity.ActivityService +import io.tolgee.activity.groups.ActivityGroupService +import io.tolgee.dtos.queryResults.ActivityGroupView import io.tolgee.exceptions.NotFoundException +import io.tolgee.hateoas.activity.ActivityGroupModel +import io.tolgee.hateoas.activity.ActivityGroupModelAssembler import io.tolgee.hateoas.activity.ModifiedEntityModel import io.tolgee.hateoas.activity.ModifiedEntityModelAssembler import io.tolgee.hateoas.activity.ProjectActivityModel @@ -44,6 +48,9 @@ class ProjectActivityController( private val modificationResourcesAssembler: PagedResourcesAssembler, private val projectActivityModelAssembler: ProjectActivityModelAssembler, private val modifiedEntityModelAssembler: ModifiedEntityModelAssembler, + private val activityGroupService: ActivityGroupService, + private val groupPagedResourcesAssembler: PagedResourcesAssembler, + private val groupModelAssembler: ActivityGroupModelAssembler ) { @Operation(summary = "Get project activity") @GetMapping("", produces = [MediaTypes.HAL_JSON_VALUE]) @@ -101,8 +108,8 @@ class ProjectActivityController( @AllowApiAccess fun getActivityGroups( @ParameterObject pageable: Pageable, - ): PagedModel { - val views = activityService.getProjectActivity(projectId = projectHolder.project.id, pageable) - return activityPagedResourcesAssembler.toModel(views, projectActivityModelAssembler) + ): PagedModel { + val views = activityGroupService.getProjectActivityGroups(projectId = projectHolder.project.id, pageable) + return groupPagedResourcesAssembler.toModel(views, groupModelAssembler) } } diff --git a/backend/api/src/main/kotlin/io/tolgee/hateoas/activity/ActivityGroupModel.kt b/backend/api/src/main/kotlin/io/tolgee/hateoas/activity/ActivityGroupModel.kt new file mode 100644 index 0000000000..d314254b19 --- /dev/null +++ b/backend/api/src/main/kotlin/io/tolgee/hateoas/activity/ActivityGroupModel.kt @@ -0,0 +1,18 @@ +package io.tolgee.hateoas.activity + +import io.tolgee.activity.groups.ActivityGroupType +import io.tolgee.hateoas.userAccount.SimpleUserAccountModel +import org.springframework.hateoas.RepresentationModel +import org.springframework.hateoas.server.core.Relation +import java.io.Serializable + +@Suppress("unused") +@Relation(collectionRelation = "groups", itemRelation = "group") +class ActivityGroupModel( + val id: Long, + val timestamp: Long, + val type: ActivityGroupType, + val author: SimpleUserAccountModel?, + val counts: Map?, + val data: Any?, +) : RepresentationModel(), Serializable diff --git a/backend/api/src/main/kotlin/io/tolgee/hateoas/activity/ActivityGroupModelAssembler.kt b/backend/api/src/main/kotlin/io/tolgee/hateoas/activity/ActivityGroupModelAssembler.kt new file mode 100644 index 0000000000..9e7d924a9e --- /dev/null +++ b/backend/api/src/main/kotlin/io/tolgee/hateoas/activity/ActivityGroupModelAssembler.kt @@ -0,0 +1,29 @@ +package io.tolgee.hateoas.activity + +import io.tolgee.api.IProjectActivityModel +import io.tolgee.api.IProjectActivityModelAssembler +import io.tolgee.dtos.queryResults.ActivityGroupView +import io.tolgee.hateoas.userAccount.SimpleUserAccountModel +import io.tolgee.hateoas.userAccount.SimpleUserAccountModelAssembler +import io.tolgee.model.views.activity.ProjectActivityView +import io.tolgee.service.AvatarService +import org.springframework.hateoas.server.RepresentationModelAssembler +import org.springframework.stereotype.Component + +@Component +class ActivityGroupModelAssembler( + private val simpleUserAccountModelAssembler: SimpleUserAccountModelAssembler +) : RepresentationModelAssembler { + override fun toModel(view: ActivityGroupView): ActivityGroupModel { + return ActivityGroupModel( + id = view.id, + timestamp = view.timestamp.time, + type = view.type, + author = simpleUserAccountModelAssembler.toModel( + view.author + ), + counts = view.counts, + data = view.data, + ) + } +} diff --git a/backend/api/src/main/kotlin/io/tolgee/hateoas/language/LanguageModel.kt b/backend/api/src/main/kotlin/io/tolgee/hateoas/language/LanguageModel.kt index cb7b7ebe4c..50aa7b38ba 100644 --- a/backend/api/src/main/kotlin/io/tolgee/hateoas/language/LanguageModel.kt +++ b/backend/api/src/main/kotlin/io/tolgee/hateoas/language/LanguageModel.kt @@ -1,21 +1,22 @@ package io.tolgee.hateoas.language import io.swagger.v3.oas.annotations.media.Schema +import io.tolgee.api.ILanguageModel import org.springframework.hateoas.RepresentationModel import org.springframework.hateoas.server.core.Relation @Suppress("unused") @Relation(collectionRelation = "languages", itemRelation = "language") open class LanguageModel( - val id: Long, + override val id: Long, @Schema(example = "Czech", description = "Language name in english") - val name: String, + override val name: String, @Schema(example = "cs-CZ", description = "Language tag according to BCP 47 definition") - var tag: String, + override var tag: String, @Schema(example = "čeština", description = "Language name in this language") - var originalName: String? = null, + override var originalName: String?, @Schema(example = "\uD83C\uDDE8\uD83C\uDDFF", description = "Language flag emoji as UTF-8 emoji") - var flagEmoji: String? = null, + override var flagEmoji: String?, @Schema(example = "false", description = "Whether is base language of project") var base: Boolean, -) : RepresentationModel() +) : RepresentationModel(), ILanguageModel diff --git a/backend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/SimpleUserAccountModel.kt b/backend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/SimpleUserAccountModel.kt index ecf53b02e4..9616fd5537 100644 --- a/backend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/SimpleUserAccountModel.kt +++ b/backend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/SimpleUserAccountModel.kt @@ -6,7 +6,7 @@ import org.springframework.hateoas.RepresentationModel data class SimpleUserAccountModel( val id: Long, val username: String, - var name: String?, + var name: String, var avatar: Avatar?, var deleted: Boolean, ) : RepresentationModel() diff --git a/backend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/SimpleUserAccountModelAssembler.kt b/backend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/SimpleUserAccountModelAssembler.kt index f7c10b3a56..2654f2113e 100644 --- a/backend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/SimpleUserAccountModelAssembler.kt +++ b/backend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/SimpleUserAccountModelAssembler.kt @@ -1,5 +1,6 @@ package io.tolgee.hateoas.userAccount +import io.tolgee.api.SimpleUserAccount import io.tolgee.api.v2.controllers.V2UserController import io.tolgee.dtos.cacheable.UserAccountDto import io.tolgee.model.UserAccount @@ -10,11 +11,11 @@ import org.springframework.stereotype.Component @Component class SimpleUserAccountModelAssembler( private val avatarService: AvatarService, -) : RepresentationModelAssemblerSupport( +) : RepresentationModelAssemblerSupport( V2UserController::class.java, SimpleUserAccountModel::class.java, ) { - override fun toModel(entity: UserAccount): SimpleUserAccountModel { + override fun toModel(entity: SimpleUserAccount): SimpleUserAccountModel { val avatar = avatarService.getAvatarLinks(entity.avatarHash) return SimpleUserAccountModel( @@ -22,7 +23,7 @@ class SimpleUserAccountModelAssembler( username = entity.username, name = entity.name, avatar = avatar, - deleted = entity.deletedAt != null, + deleted = entity.deleted, ) } diff --git a/backend/app/src/test/kotlin/io/tolgee/activity/groups/ProjectCreationGroupViewTest.kt b/backend/app/src/test/kotlin/io/tolgee/activity/groups/ProjectCreationGroupViewTest.kt new file mode 100644 index 0000000000..fc04294c6c --- /dev/null +++ b/backend/app/src/test/kotlin/io/tolgee/activity/groups/ProjectCreationGroupViewTest.kt @@ -0,0 +1,107 @@ +package io.tolgee.activity.groups + +import io.tolgee.batch.BatchJobService +import io.tolgee.development.testDataBuilder.data.BaseTestData +import io.tolgee.dtos.request.LanguageRequest +import io.tolgee.dtos.request.project.CreateProjectRequest +import io.tolgee.fixtures.andAssertThatJson +import io.tolgee.fixtures.andGetContentAsJsonMap +import io.tolgee.fixtures.andIsOk +import io.tolgee.fixtures.isValidId +import io.tolgee.fixtures.node +import io.tolgee.model.key.Key +import io.tolgee.testing.AuthorizedControllerTest +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import java.math.BigDecimal + +class ProjectCreationGroupViewTest : AuthorizedControllerTest() { + private lateinit var testData: BaseTestData + + @Autowired + lateinit var batchJobService: BatchJobService + + lateinit var key: Key + + private fun prepareTestData() { + testData = BaseTestData() + testDataService.saveTestData(testData.root) + } + + @Test + fun `shows correct project creation group`() { + prepareTestData() + userAccount = testData.user + val projectId = performProjectCreation() + performAuthGet("/v2/projects/$projectId/activity/groups") + .andIsOk.andAssertThatJson { + node("_embedded.groups") { + isArray.hasSizeGreaterThan(0) + node("[0]") { + node("id").isNumber + node("timestamp").isNumber.isGreaterThan(BigDecimal("1722441564241")) + node("type").isEqualTo("CREATE_PROJECT") + + node("author") { + node("id").isNumber + node("username").isEqualTo("test_username") + node("name").isEqualTo("") + node("avatar").isNull() + node("deleted").isEqualTo(false) + } + + node("counts.Project").isEqualTo(1) + + node("data") { + node("id").isNumber + node("name").isEqualTo("What a project") + node("languages") { + isArray.hasSize(2) + node("[0]") { + node("id").isValidId + node("name").isEqualTo("English") + node("originalName").isEqualTo("English") + node("tag").isEqualTo("en") + node("flagEmoji").isEqualTo("a") + } + node("[1]") { + node("id").isValidId + node("name").isEqualTo("Czech") + node("originalName").isEqualTo("česky") + node("tag").isEqualTo("cs") + node("flagEmoji").isEqualTo("b") + } + } + node("description").isNull() + } + } + } + } + } + + private fun performProjectCreation(): Int { + return performAuthPost( + "/v2/projects", + CreateProjectRequest( + name = "What a project", + organizationId = testData.project.organizationOwner.id, + languages = + listOf( + LanguageRequest( + name = "English", + originalName = "English", + tag = "en", + flagEmoji = "a", + ), + LanguageRequest( + name = "Czech", + originalName = "česky", + tag = "cs", + flagEmoji = "b", + ), + ), + baseLanguageTag = "cs", + ), + ).andIsOk.andGetContentAsJsonMap["id"] as Int + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/ActivityHolder.kt b/backend/data/src/main/kotlin/io/tolgee/activity/ActivityHolder.kt index e6860cf2ca..4416030fb7 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/ActivityHolder.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/ActivityHolder.kt @@ -8,6 +8,7 @@ import io.tolgee.model.activity.ActivityModifiedEntity import io.tolgee.model.activity.ActivityRevision import jakarta.annotation.PreDestroy import org.springframework.context.ApplicationContext +import java.util.IdentityHashMap import kotlin.reflect.KClass open class ActivityHolder(val applicationContext: ApplicationContext) { @@ -69,4 +70,4 @@ open class ActivityHolder(val applicationContext: ApplicationContext) { } } -typealias ModifiedEntitiesType = MutableMap, MutableMap> +typealias ModifiedEntitiesType = MutableMap, IdentityHashMap> diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/ActivityService.kt b/backend/data/src/main/kotlin/io/tolgee/activity/ActivityService.kt index d683c9669f..a78d0195be 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/ActivityService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/ActivityService.kt @@ -53,7 +53,7 @@ class ActivityService( } private fun persistModifiedEntities(modifiedEntities: ModifiedEntitiesType): MutableList { - val list = modifiedEntities.values.flatMap { it.values }.toMutableList() + val list = modifiedEntities.values.flatMap { it.entries }.toMutableList() jdbcTemplate.batchUpdate( "INSERT INTO activity_modified_entity " + "(entity_class, entity_id, describing_data, " + @@ -61,17 +61,19 @@ class ActivityService( "VALUES (?, ?, ?, ?, ?, ?, ?)", list, 100, - ) { ps, entity -> - ps.setString(1, entity.entityClass) - ps.setLong(2, entity.entityId) - ps.setObject(3, getJsonbObject(entity.describingData)) - ps.setObject(4, getJsonbObject(entity.describingRelations)) - ps.setObject(5, getJsonbObject(entity.modifications)) - ps.setInt(6, RevisionType.values().indexOf(entity.revisionType)) - ps.setLong(7, entity.activityRevision.id) + ) { ps, (entityInstance, modifiedEntity) -> + // the entity id can be null in some cases (probably when the id it's not allocated in batch) + val entityId = if (modifiedEntity.entityId == 0L) entityInstance.id else modifiedEntity.entityId + ps.setString(1, modifiedEntity.entityClass) + ps.setLong(2, entityId) + ps.setObject(3, getJsonbObject(modifiedEntity.describingData)) + ps.setObject(4, getJsonbObject(modifiedEntity.describingRelations)) + ps.setObject(5, getJsonbObject(modifiedEntity.modifications)) + ps.setInt(6, RevisionType.values().indexOf(modifiedEntity.revisionType)) + ps.setLong(7, modifiedEntity.activityRevision.id) } - return list + return list.map { it.value }.toMutableList() } private fun persistedDescribingRelations(activityRevision: ActivityRevision) { diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupService.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupService.kt index c3ba137b55..62bc709010 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupService.kt @@ -28,7 +28,7 @@ class ActivityGroupService( ActivityGrouper(activityRevision, modifiedEntities, applicationContext).addToGroup() } - fun getOrCreateCurrentActivityGroupDtos( + fun getOrCreateCurrentActivityGroupDto( type: ActivityGroupType, projectId: Long?, authorId: Long?, diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupType.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupType.kt index 73ba922d3e..99d35f6e8b 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupType.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupType.kt @@ -5,6 +5,7 @@ import io.tolgee.activity.data.RevisionType import io.tolgee.activity.groups.matchers.ActivityGroupValueMatcher.Companion.eq import io.tolgee.activity.groups.matchers.ActivityGroupValueMatcher.Companion.modification import io.tolgee.activity.groups.matchers.ActivityGroupValueMatcher.Companion.notNull +import io.tolgee.activity.groups.viewProviders.createProject.CreateProjectGroupModelProvider import io.tolgee.model.Language import io.tolgee.model.Project import io.tolgee.model.Screenshot @@ -19,10 +20,12 @@ import io.tolgee.model.key.screenshotReference.KeyScreenshotReference import io.tolgee.model.translation.Translation import io.tolgee.model.translation.TranslationComment import io.tolgee.model.webhook.WebhookConfig +import org.springframework.context.ApplicationContext enum class ActivityGroupType( val sourceActivityTypes: List, val modifications: List>, + val modelProviderFactory: ((ApplicationContext) -> GroupModelProvider<*>?)? = null, ) { SET_TRANSLATION_STATE( listOf(ActivityType.SET_TRANSLATION_STATE, ActivityType.COMPLEX_EDIT), @@ -304,6 +307,7 @@ enum class ActivityGroupType( countInView = true, ), ), + modelProviderFactory = { ac -> CreateProjectGroupModelProvider(ac) }, ), EDIT_PROJECT( diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGrouper.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGrouper.kt index 4558952018..bffffc59c5 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGrouper.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGrouper.kt @@ -8,6 +8,7 @@ import io.tolgee.model.activity.ActivityModifiedEntity import io.tolgee.model.activity.ActivityRevision import jakarta.persistence.EntityManager import org.springframework.context.ApplicationContext +import java.util.IdentityHashMap import kotlin.reflect.KClass import kotlin.reflect.KProperty1 @@ -19,7 +20,7 @@ class ActivityGrouper( fun addToGroup() { val groupTypes = findGroupTypes() groupTypes.forEach { - val groupIdToAddTo = getActivityGroupIds(it) + val groupIdToAddTo = getActivityGroupId(it) addToGroup(groupIdToAddTo) } } @@ -36,8 +37,8 @@ class ActivityGrouper( .executeUpdate() } - private fun getActivityGroupIds(type: ActivityGroupType): Long { - return activityGroupService.getOrCreateCurrentActivityGroupDtos( + private fun getActivityGroupId(type: ActivityGroupType): Long { + return activityGroupService.getOrCreateCurrentActivityGroupDto( type, activityRevision.projectId, activityRevision.authorId, @@ -119,4 +120,4 @@ class ActivityGrouper( } } -private typealias ModifiedEntityType = Map.Entry, MutableMap> +private typealias ModifiedEntityType = Map.Entry, IdentityHashMap> diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupsProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupsProvider.kt index ffa16bae17..7a87290290 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupsProvider.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupsProvider.kt @@ -2,6 +2,7 @@ package io.tolgee.activity.groups import io.tolgee.activity.groups.matchers.ActivityGroupValueMatcher import io.tolgee.activity.groups.matchers.EqualsValueMatcher +import io.tolgee.api.SimpleUserAccount import io.tolgee.dtos.queryResults.ActivityGroupView import org.jooq.Condition import org.jooq.DSLContext @@ -19,8 +20,8 @@ import java.util.* class ActivityGroupsProvider(val projectId: Long, val pageable: Pageable, applicationContext: ApplicationContext) { fun get(): PageImpl { page.forEach { - val counts = counts[it.id] ?: emptyMap() - it.counts = counts + it.counts = counts[it.id] ?: emptyMap() + it.data = dataViews[it.id] } return page @@ -38,14 +39,20 @@ class ActivityGroupsProvider(val projectId: Long, val pageable: Pageable, applic field("ag.type"), field("ag.author_id"), max(field("ar.timestamp")), + field("ua.id"), + field("ua.username"), + field("ua.name"), + field("ua.avatar_hash"), + field("ua.deleted_at").isNotNull, ) .from(from) .leftJoin(table("activity_revision_activity_groups").`as`("arag")) .on(field("ag.id").eq(field("arag.activity_groups_id"))) .leftJoin(table("activity_revision").`as`("ar")) .on(field("ar.id").eq(field("arag.activity_revisions_id"))) + .leftJoin(table("user_account").`as`("ua")).on(field("ag.author_id").eq(field("ua.id"))) .where(where) - .groupBy(field("ag.id")) + .groupBy(field("ag.id"), field("ua.id")) .orderBy(max(field("ar.timestamp")).desc()) .limit(pageable.pageSize) .offset(pageable.offset).fetch().map { @@ -53,6 +60,13 @@ class ActivityGroupsProvider(val projectId: Long, val pageable: Pageable, applic it[0] as Long, ActivityGroupType.valueOf(it[1] as String), it[3] as Date, + author = object : SimpleUserAccount { + override val id: Long = it[4] as Long + override val username: String = it[5] as String + override val name: String = it[6] as String + override val avatarHash: String? = it[7] as String? + override val deleted: Boolean = it[8] as Boolean + } ) } @@ -60,12 +74,20 @@ class ActivityGroupsProvider(val projectId: Long, val pageable: Pageable, applic } private val counts by lazy { - val byType = page.groupBy { it.type } byType.flatMap { (type, items) -> getCounts(type, items).map { it.key to it.value } }.toMap() } + private val dataViews by lazy { + byType.flatMap { (type, items) -> + val provider = type.modelProviderFactory?.invoke(applicationContext) + provider?.provide(items.map { it.id })?.map { it.key to it.value } ?: emptyList() + }.toMap() + } + + private val byType by lazy { page.groupBy { it.type } } + private fun getModificationCondition(definition: GroupEntityModificationDefinition<*>): Condition { return field("ame.entity_class").eq(definition.entityClass.simpleName) .and(field("ame.revision_type").`in`(definition.revisionTypes.map { it.ordinal })) @@ -113,9 +135,9 @@ class ActivityGroupsProvider(val projectId: Long, val pageable: Pageable, applic private fun getCounts( type: ActivityGroupType, items: List, - ): MutableMap> { + ): MutableMap> { val groupIds = items.map { it.id } - val result = mutableMapOf>() + val result = mutableMapOf>() type.modifications .filter { it.countInView } .forEach { definition -> @@ -134,7 +156,7 @@ class ActivityGroupsProvider(val projectId: Long, val pageable: Pageable, applic result.computeIfAbsent(it[0] as Long) { mutableMapOf() } - groupMap[definition.entityClass.simpleName!!] = it[1] as Int + groupMap[definition.entityClass.simpleName!!] = (it[1] as Int).toLong() } } return result diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/GroupModelProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/GroupModelProvider.kt new file mode 100644 index 0000000000..0872c8bb82 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/GroupModelProvider.kt @@ -0,0 +1,5 @@ +package io.tolgee.activity.groups + +interface GroupModelProvider { + fun provide(groupIds: List): Map +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/CreateProjectGroupModel.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/CreateProjectGroupModel.kt new file mode 100644 index 0000000000..9f8a1a69a2 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/CreateProjectGroupModel.kt @@ -0,0 +1,8 @@ +package io.tolgee.activity.groups.viewProviders.createProject + +class CreateProjectGroupModel( + val id: Long, + val name: String, + val languages: List, + val description: String?, +) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/CreateProjectGroupModelProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/CreateProjectGroupModelProvider.kt new file mode 100644 index 0000000000..74ced4750d --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/CreateProjectGroupModelProvider.kt @@ -0,0 +1,58 @@ +package io.tolgee.activity.groups.viewProviders.createProject + +import io.tolgee.activity.groups.GroupModelProvider +import org.jooq.DSLContext +import org.jooq.impl.DSL +import org.springframework.context.ApplicationContext + +class CreateProjectGroupModelProvider(applicationContext: ApplicationContext) : + GroupModelProvider { + override fun provide(groupIds: List): Map { + val query = jooqContext + .select( + DSL.field("arag.activity_groups_id", Long::class.java).`as`("groupId"), + DSL.field("pme.modifications -> 'name' ->> 'new'", String::class.java).`as`("name"), + DSL.field("pme.modifications -> 'description' ->> 'new'", String::class.java).`as`("description"), + DSL.field("pme.entity_id").`as`("id"), + DSL.field("lme.modifications -> 'name' ->> 'new'", String::class.java).`as`("languageName"), + DSL.field("lme.entity_id", Long::class.java).`as`("languageId"), + DSL.field("lme.modifications -> 'tag' ->> 'new'", String::class.java).`as`("languageTag"), + DSL.field("lme.modifications -> 'originalName' ->> 'new'", String::class.java).`as`("languageOriginalName"), + DSL.field("lme.modifications -> 'flagEmoji' ->> 'new'", String::class.java).`as`("languageFlagEmoji") + ) + .from(DSL.table("activity_modified_entity").`as`("pme")) + .join(DSL.table("activity_revision").`as`("ar")) + .on(DSL.field("pme.activity_revision_id").eq(DSL.field("ar.id"))) + .join(DSL.table("activity_revision_activity_groups").`as`("arag")) + .on(DSL.field("ar.id").eq(DSL.field("arag.activity_revisions_id"))) + .join(DSL.table("activity_modified_entity").`as`("lme")) + .on( + DSL.field("lme.entity_class").eq(DSL.inline("Language")) + .and(DSL.field("lme.activity_revision_id").eq(DSL.field("ar.id"))) + ) + .where(DSL.field("arag.activity_groups_id").`in`(groupIds)) + .and(DSL.field("pme.entity_class").eq(DSL.inline("Project"))) + .fetch() + + return query.groupBy { it["groupId"] as Long }.map { (id, rows) -> + val languages = rows.map { + LanguageModel( + it["languageId"] as Long, + it["languageName"] as String, + it["languageOriginalName"] as String, + it["languageTag"] as String, + it["languageFlagEmoji"] as String + ) + } + + id to CreateProjectGroupModel( + id = id, + name = rows.first()["name"] as String, + description = rows.first()["description"] as String?, + languages = languages + ) + }.toMap() + } + + private val jooqContext = applicationContext.getBean(DSLContext::class.java) +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/LanguageModel.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/LanguageModel.kt new file mode 100644 index 0000000000..624bd1342f --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/LanguageModel.kt @@ -0,0 +1,11 @@ +package io.tolgee.activity.groups.viewProviders.createProject + +import io.tolgee.api.ILanguageModel + +class LanguageModel( + override val id: Long, + override val name: String, + override val originalName: String, + override val tag: String, + override val flagEmoji: String +) : ILanguageModel diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/iterceptor/InterceptedEventsManager.kt b/backend/data/src/main/kotlin/io/tolgee/activity/iterceptor/InterceptedEventsManager.kt index 54dae5e62d..a12293756e 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/iterceptor/InterceptedEventsManager.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/iterceptor/InterceptedEventsManager.kt @@ -31,6 +31,7 @@ import org.springframework.beans.factory.config.BeanDefinition.SCOPE_SINGLETON import org.springframework.context.ApplicationContext import org.springframework.context.annotation.Scope import org.springframework.stereotype.Component +import java.util.IdentityHashMap import kotlin.reflect.KCallable import kotlin.reflect.full.findAnnotation import kotlin.reflect.full.hasAnnotation @@ -116,7 +117,11 @@ class InterceptedEventsManager( val changesMap = getChangesMap(entity, currentState, previousState, propertyNames) - activityModifiedEntity.revisionType = revisionType + activityModifiedEntity.revisionType = when { + // when we are replacing ADD with MOD, we want to keep ADD + activityModifiedEntity.revisionType == RevisionType.ADD && revisionType == RevisionType.MOD -> RevisionType.ADD + else -> revisionType + } activityModifiedEntity.modifications.putAll(changesMap) activityModifiedEntity.setEntityDescription(entity) @@ -150,9 +155,9 @@ class InterceptedEventsManager( ): ActivityModifiedEntity { val activityModifiedEntity = activityHolder.modifiedEntities - .computeIfAbsent(entity::class) { mutableMapOf() } + .computeIfAbsent(entity::class) { IdentityHashMap() } .computeIfAbsent( - entity.id, + entity ) { ActivityModifiedEntity( activityRevision, diff --git a/backend/data/src/main/kotlin/io/tolgee/api/ILanguageModel.kt b/backend/data/src/main/kotlin/io/tolgee/api/ILanguageModel.kt new file mode 100644 index 0000000000..5c377a7e1a --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/api/ILanguageModel.kt @@ -0,0 +1,9 @@ +package io.tolgee.api + +interface ILanguageModel { + val id: Long + val name: String + val tag: String + val originalName: String? + val flagEmoji: String? +} diff --git a/backend/data/src/main/kotlin/io/tolgee/api/SimpleUserAccount.kt b/backend/data/src/main/kotlin/io/tolgee/api/SimpleUserAccount.kt new file mode 100644 index 0000000000..a07e1a2200 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/api/SimpleUserAccount.kt @@ -0,0 +1,9 @@ +package io.tolgee.api + +interface SimpleUserAccount { + val id: Long + val username: String + val name: String + val deleted: Boolean + val avatarHash: String? +} diff --git a/backend/data/src/main/kotlin/io/tolgee/dtos/queryResults/ActivityGroupView.kt b/backend/data/src/main/kotlin/io/tolgee/dtos/queryResults/ActivityGroupView.kt index 2a57ab84dc..d38e657a11 100644 --- a/backend/data/src/main/kotlin/io/tolgee/dtos/queryResults/ActivityGroupView.kt +++ b/backend/data/src/main/kotlin/io/tolgee/dtos/queryResults/ActivityGroupView.kt @@ -1,6 +1,7 @@ package io.tolgee.dtos.queryResults import io.tolgee.activity.groups.ActivityGroupType +import io.tolgee.api.SimpleUserAccount data class ActivityGroupView( val id: Long, @@ -9,5 +10,7 @@ data class ActivityGroupView( /** * Counts of items in this group by entity class name */ - var counts: Map? = null, + var counts: Map? = null, + var data: Any? = null, + var author: SimpleUserAccount ) diff --git a/backend/data/src/main/kotlin/io/tolgee/dtos/queryResults/TranslationHistoryView.kt b/backend/data/src/main/kotlin/io/tolgee/dtos/queryResults/TranslationHistoryView.kt index f6722d2ab6..59110db247 100644 --- a/backend/data/src/main/kotlin/io/tolgee/dtos/queryResults/TranslationHistoryView.kt +++ b/backend/data/src/main/kotlin/io/tolgee/dtos/queryResults/TranslationHistoryView.kt @@ -7,7 +7,7 @@ import java.util.* interface TranslationHistoryView { var modifications: Map? var timestamp: Date - var authorName: String? + var authorName: String var authorAvatarHash: String? var authorEmail: String? var authorDeletedAt: Date? diff --git a/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt b/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt index c7a0ca09d2..92076c712d 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt @@ -2,6 +2,7 @@ package io.tolgee.model import io.hypersistence.utils.hibernate.type.array.ListArrayType import io.tolgee.api.IUserAccount +import io.tolgee.api.SimpleUserAccount import io.tolgee.model.slackIntegration.SlackConfig import io.tolgee.model.slackIntegration.SlackUserConnection import io.tolgee.model.notifications.NotificationPreferences @@ -30,15 +31,15 @@ data class UserAccount( @GeneratedValue(strategy = GenerationType.IDENTITY) override var id: Long = 0L, @field:NotBlank - var username: String = "", + override var username: String = "", var password: String? = null, - var name: String = "", + override var name: String = "", @Enumerated(EnumType.STRING) var role: Role? = Role.USER, @Enumerated(EnumType.STRING) @Column(name = "account_type") override var accountType: AccountType? = AccountType.LOCAL, -) : AuditModel(), ModelWithAvatar, IUserAccount { +) : AuditModel(), ModelWithAvatar, IUserAccount, SimpleUserAccount { @Column(name = "totp_key", columnDefinition = "bytea") override var totpKey: ByteArray? = null @@ -116,6 +117,9 @@ data class UserAccount( @OneToMany(fetch = FetchType.LAZY, cascade = [CascadeType.REMOVE], orphanRemoval = true, mappedBy = "userAccount") private var _globalNotificationPreferences: MutableList = mutableListOf() + override val deleted: Boolean + get() = deletedAt != null + constructor( id: Long?, username: String?, diff --git a/webapp/package.json b/webapp/package.json index 832ac9be0f..2b2bcc3ccc 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -5,16 +5,18 @@ "type": "module", "dependencies": { "@codemirror/lang-json": "6.0.0", - "@dicebear/core": "^7.0.4", - "@dicebear/identicon": "^7.0.4", - "@dicebear/initials": "^7.0.4", - "@emotion/react": "^11.11.3", + "@dicebear/avatars": "4.10.2", + "@dicebear/avatars-identicon-sprites": "4.10.2", + "@dicebear/avatars-initials-sprites": "4.10.2", + "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", "@formatjs/icu-messageformat-parser": "^2.0.8", - "@mui/icons-material": "^5.15.7", - "@mui/lab": "^5.0.0-alpha.163", - "@mui/material": "^5.15.7", - "@mui/x-date-pickers": "^5.0.20", + "@mdx-js/rollup": "^3.0.0", + "@mui/icons-material": "^5.5.1", + "@mui/lab": "^5.0.0-alpha.75", + "@mui/material": "^5.5.3", + "@mui/x-date-pickers": "5.0.0-beta.6", + "@openreplay/tracker": "^3.5.4", "@sentry/browser": "^7.80.0", "@stomp/stompjs": "^6.1.2", "@tginternal/editor": "^1.15.1", @@ -30,11 +32,15 @@ "dotenv-flow": "4.0.1", "formik": "^2.2.9", "intl-messageformat": "^9.8.1", + "node-fetch": "3.3.0", "notistack": "^2.0.4", "posthog-js": "^1.96.1", - "prism-react-renderer": "^2.3.1", + "prism-react-renderer": "1.2.1", + "prism-svelte": "0.4.7", "react": "^17.0.1", - "react-cropper": "^2.3.3", + "react-cropper": "2.1.8", + "react-dnd": "^14.0.2", + "react-dnd-html5-backend": "^14.0.0", "react-dom": "^17.0.2", "react-draggable": "^4.4.3", "react-google-recaptcha-v3": "1.9.5", @@ -46,7 +52,7 @@ "react-qr-code": "^2.0.7", "react-query": "^3.39.2", "react-router-dom": "^5.2.0", - "recharts": "^2.11.0", + "recharts": "2.1.9", "reflect-metadata": "^0.1.13", "regenerator-runtime": "^0.13.9", "sockjs-client": "^1.6.1", @@ -98,7 +104,7 @@ ] }, "devDependencies": { - "@mdx-js/rollup": "^3.0.0", + "@mdx-js/loader": "1.6.22", "@sentry/types": "^6.5.1", "@testing-library/jest-dom": "^5.14.1", "@testing-library/react": "^12.0.0", @@ -123,21 +129,13 @@ "husky": "^9.0.11", "openapi-typescript": "^4.0.2", "prettier": "^2.3.1", - "@redux-devtools/extension": "^3.3.0", + "redux-devtools-extension": "^2.13.9", "rehype-highlight": "^7.0.0", "ts-unused-exports": "^9.0.4", "typescript": "^5.3.3", - "vite": "^5.0.12", + "vite-plugin-node-polyfills": "^0.19.0", "vite-plugin-static-copy": "^1.0.0", "vite-plugin-svgr": "^4.2.0", "vite-tsconfig-paths": "^4.2.3" - }, - "overrides": { - "vite": { - "rollup": "npm:@rollup/wasm-node" - }, - "@mdx-js/rollup": { - "rollup": "npm:@rollup/wasm-node" - } } } diff --git a/webapp/src/component/RootRouter.tsx b/webapp/src/component/RootRouter.tsx index fbe0af4c84..3e7bba1ce3 100644 --- a/webapp/src/component/RootRouter.tsx +++ b/webapp/src/component/RootRouter.tsx @@ -10,8 +10,6 @@ import { UserSettingsRouter } from 'tg.views/userSettings/UserSettingsRouter'; import { OrganizationsRouter } from 'tg.views/organizations/OrganizationsRouter'; import { useConfig } from 'tg.globalContext/helpers'; import { AdministrationView } from 'tg.views/administration/AdministrationView'; - -import { PrivateRoute } from './common/PrivateRoute'; import { OrganizationBillingRedirect } from './security/OrganizationBillingRedirect'; import { RequirePreferredOrganization } from '../RequirePreferredOrganization'; import { HelpMenu } from './HelpMenu'; diff --git a/webapp/src/component/common/avatar/useAutoAvatarImgSrc.tsx b/webapp/src/component/common/avatar/useAutoAvatarImgSrc.tsx index f14121cec0..c4e6be98a5 100644 --- a/webapp/src/component/common/avatar/useAutoAvatarImgSrc.tsx +++ b/webapp/src/component/common/avatar/useAutoAvatarImgSrc.tsx @@ -1,61 +1,17 @@ import { useEffect, useState } from 'react'; import { AutoAvatarProps } from './AutoAvatar'; -import { colors } from '@mui/material'; - -const COLORS_LIGHT = [ - colors.amber[300], - colors.blue[300], - colors.blueGrey[300], - colors.brown[300], - colors.common[300], - colors.cyan[300], - colors.deepOrange[300], - colors.deepPurple[300], - colors.green[300], - colors.grey[300], - colors.indigo[300], - colors.lightBlue[300], - colors.lightGreen[300], - colors.lime[300], - colors.orange[300], - colors.pink[300], - colors.purple[300], - colors.red[300], - colors.teal[300], -]; - -const COLORS_DARK = [ - colors.amber[700], - colors.blue[700], - colors.blueGrey[700], - colors.brown[700], - colors.common[700], - colors.cyan[700], - colors.deepOrange[700], - colors.deepPurple[700], - colors.green[700], - colors.grey[700], - colors.indigo[700], - colors.lightBlue[700], - colors.lightGreen[700], - colors.lime[700], - colors.orange[700], - colors.pink[700], - colors.purple[700], - colors.red[700], - colors.teal[700], -]; +import { Buffer } from 'buffer'; function getInitialsAvatarSvg(ownerName: string, size: number, light: boolean) { return Promise.all([ importCreateAvatarFunction(), - import('@dicebear/initials'), + import('@dicebear/avatars-initials-sprites'), ]).then(([crateAvatar, style]) => { return crateAvatar(style, { seed: ownerName, size, scale: 100, - backgroundColor: light ? COLORS_LIGHT : COLORS_DARK, + backgroundColorLevel: light ? 300 : 700, }); }); } @@ -63,7 +19,7 @@ function getInitialsAvatarSvg(ownerName: string, size: number, light: boolean) { function getIdenticonAvatarSvg(entityId: number | string, size: number) { return Promise.all([ importCreateAvatarFunction(), - import('@dicebear/identicon'), + import('@dicebear/avatars-identicon-sprites'), ]).then(([crateAvatar, style]) => { return crateAvatar(style, { seed: entityId.toString(), @@ -74,7 +30,7 @@ function getIdenticonAvatarSvg(entityId: number | string, size: number) { } export const useAutoAvatarImgSrc = (props: AutoAvatarProps) => { - const [url, setUrl] = useState(undefined as string | undefined); + const [base64, setBase64] = useState(undefined as string | undefined); useEffect(() => { let mounted = true; @@ -87,17 +43,24 @@ export const useAutoAvatarImgSrc = (props: AutoAvatarProps) => { props.ownerType === 'PROJECT' ); - svgStringPromise.then((svg) => { - if (mounted) setUrl(svg.toDataUriSync()); + svgStringPromise.then((svgString) => { + const base64 = Buffer.from(svgString).toString('base64'); + if (mounted) { + setBase64(base64); + } }); return () => { mounted = false; }; }, [props.size, props.entityId, props.ownerName, props.ownerType]); - return url; + if (!base64) { + return undefined; + } + + return `data:image/svg+xml;base64,${base64}`; }; function importCreateAvatarFunction() { - return import('@dicebear/core').then((m) => m.createAvatar); + return import('@dicebear/avatars').then((m) => m.createAvatar); } diff --git a/webapp/src/service/apiSchema.generated.ts b/webapp/src/service/apiSchema.generated.ts index 0ad67c7fbc..f1d40fec74 100644 --- a/webapp/src/service/apiSchema.generated.ts +++ b/webapp/src/service/apiSchema.generated.ts @@ -270,6 +270,15 @@ export interface paths { put: operations["uploadAvatar_2"]; delete: operations["removeAvatar_2"]; }; + "/v2/notifications/preferences/project/{id}": { + get: operations["getPerProjectPreferences"]; + put: operations["updatePerProjectPreferences"]; + delete: operations["deletePerProjectPreferences"]; + }; + "/v2/notifications/preferences/global": { + get: operations["getGlobalPreferences"]; + put: operations["updateGlobalPreferences"]; + }; "/v2/ee-license/set-license-key": { put: operations["setLicenseKey"]; }; @@ -508,6 +517,27 @@ export interface paths { */ post: operations["connectWorkspace"]; }; + "/v2/notifications/unmark-as-done": { + post: operations["unmarkNotificationsAsDone"]; + }; + "/v2/notifications/preferences/project/{id}/subscribe": { + post: operations["subscribeToProject"]; + }; + "/v2/notifications/mark-as-unread": { + post: operations["markNotificationsAsUnread"]; + }; + "/v2/notifications/mark-as-read": { + post: operations["markNotificationsAsRead"]; + }; + "/v2/notifications/mark-as-read/all": { + post: operations["markAllNotificationsAsRead"]; + }; + "/v2/notifications/mark-as-done": { + post: operations["markNotificationsAsDone"]; + }; + "/v2/notifications/mark-as-done/all": { + post: operations["markAllNotificationsAsDone"]; + }; "/v2/image-upload": { post: operations["upload"]; }; @@ -617,6 +647,10 @@ export interface paths { "/v2/projects/{projectId}/activity/revisions/{revisionId}": { get: operations["getSingleRevision"]; }; + "/v2/projects/{projectId}/activity/groups": { + /** This endpoints returns the activity grouped by time windows so it's easier to read on the frontend. */ + get: operations["getActivityGroups"]; + }; "/v2/projects/{projectId}/activity": { get: operations["getActivity"]; }; @@ -755,6 +789,12 @@ export interface paths { /** Returns all organization projects the user has access to */ get: operations["getAllProjects_1"]; }; + "/v2/notifications": { + get: operations["getNotifications"]; + }; + "/v2/notifications/preferences": { + get: operations["getAllPreferences"]; + }; "/v2/invitations/{code}/accept": { get: operations["acceptInvitation"]; }; @@ -1062,7 +1102,8 @@ export interface components { | "tolgee_account_already_connected" | "slack_not_configured" | "slack_workspace_already_connected" - | "slack_connection_error"; + | "slack_connection_error" + | "email_verification_code_not_valid"; params?: { [key: string]: unknown }[]; }; ErrorResponseBody: { @@ -1135,29 +1176,6 @@ export interface components { | "SERVER_ADMIN"; /** @description The user's permission type. This field is null if uses granular permissions */ type?: "NONE" | "VIEW" | "TRANSLATE" | "REVIEW" | "EDIT" | "MANAGE"; - /** - * @deprecated - * @description Deprecated (use translateLanguageIds). - * - * List of languages current user has TRANSLATE permission to. If null, all languages edition is permitted. - * @example 200001,200004 - */ - permittedLanguageIds?: number[]; - /** - * @description List of languages user can translate to. If null, all languages editing is permitted. - * @example 200001,200004 - */ - translateLanguageIds?: number[]; - /** - * @description List of languages user can view. If null, all languages view is permitted. - * @example 200001,200004 - */ - viewLanguageIds?: number[]; - /** - * @description List of languages user can change state to. If null, changing state of all language values is permitted. - * @example 200001,200004 - */ - stateChangeLanguageIds?: number[]; /** * @description Granted scopes to the user. When user has type permissions, this field contains permission scopes of the type. * @example KEYS_EDIT,TRANSLATIONS_VIEW @@ -1190,6 +1208,29 @@ export interface components { | "content-delivery.publish" | "webhooks.manage" )[]; + /** + * @description List of languages user can view. If null, all languages view is permitted. + * @example 200001,200004 + */ + viewLanguageIds?: number[]; + /** + * @description List of languages user can translate to. If null, all languages editing is permitted. + * @example 200001,200004 + */ + translateLanguageIds?: number[]; + /** + * @description List of languages user can change state to. If null, changing state of all language values is permitted. + * @example 200001,200004 + */ + stateChangeLanguageIds?: number[]; + /** + * @deprecated + * @description Deprecated (use translateLanguageIds). + * + * List of languages current user has TRANSLATE permission to. If null, all languages edition is permitted. + * @example 200001,200004 + */ + permittedLanguageIds?: number[]; }; LanguageModel: { /** Format: int64 */ @@ -2156,15 +2197,15 @@ export interface components { token: string; /** Format: int64 */ id: number; - description: string; /** Format: int64 */ createdAt: number; /** Format: int64 */ updatedAt: number; /** Format: int64 */ - expiresAt?: number; - /** Format: int64 */ lastUsedAt?: number; + /** Format: int64 */ + expiresAt?: number; + description: string; }; SetOrganizationRoleDto: { roleType: "MEMBER" | "OWNER"; @@ -2212,6 +2253,23 @@ export interface components { invitedUserName?: string; invitedUserEmail?: string; }; + NotificationPreferencesDto: { + /** @description List of notification types the user does not want to receive. */ + disabledNotifications: ( + | "ACTIVITY_LANGUAGES_CREATED" + | "ACTIVITY_KEYS_CREATED" + | "ACTIVITY_KEYS_UPDATED" + | "ACTIVITY_KEYS_SCREENSHOTS_UPLOADED" + | "ACTIVITY_SOURCE_STRINGS_UPDATED" + | "ACTIVITY_TRANSLATIONS_UPDATED" + | "ACTIVITY_TRANSLATION_OUTDATED" + | "ACTIVITY_TRANSLATION_REVIEWED" + | "ACTIVITY_TRANSLATION_UNREVIEWED" + | "ACTIVITY_NEW_COMMENTS" + | "ACTIVITY_COMMENTS_MENTION" + | "BATCH_JOB_ERRORED" + )[]; + }; SetLicenseKeyDto: { licenseKey: string; }; @@ -2302,17 +2360,17 @@ export interface components { key: string; /** Format: int64 */ id: number; - projectName: string; - userFullName?: string; - description: string; - username?: string; + scopes: string[]; /** Format: int64 */ projectId: number; - /** Format: int64 */ - expiresAt?: number; + username?: string; /** Format: int64 */ lastUsedAt?: number; - scopes: string[]; + /** Format: int64 */ + expiresAt?: number; + description: string; + projectName: string; + userFullName?: string; }; SuperTokenRequest: { /** @description Has to be provided when TOTP enabled */ @@ -2863,7 +2921,8 @@ export interface components { | "tolgee_account_already_connected" | "slack_not_configured" | "slack_workspace_already_connected" - | "slack_connection_error"; + | "slack_connection_error" + | "email_verification_code_not_valid"; params?: { [key: string]: unknown }[]; }; UntagKeysRequest: { @@ -3416,6 +3475,8 @@ export interface components { languageTag?: string; eeSubscription?: components["schemas"]["EeSubscriptionModel"]; announcement?: components["schemas"]["AnnouncementDto"]; + /** Format: int32 */ + unreadNotifications?: number; }; MtServiceDTO: { enabled: boolean; @@ -3466,7 +3527,7 @@ export interface components { name: string; /** Format: int64 */ id: number; - basePermissions: components["schemas"]["PermissionModel"]; + avatar?: components["schemas"]["Avatar"]; /** @example btforg */ slug: string; /** @example This is a beautiful organization full of beautiful and clever people */ @@ -3477,7 +3538,7 @@ export interface components { * Can be null when user has direct access to one of the projects owned by the organization. */ currentUserRole?: "MEMBER" | "OWNER"; - avatar?: components["schemas"]["Avatar"]; + basePermissions: components["schemas"]["PermissionModel"]; }; PublicBillingConfigurationDTO: { enabled: boolean; @@ -3614,20 +3675,20 @@ export interface components { name: string; /** Format: int64 */ id: number; - namespace?: string; + translation?: string; description?: string; + namespace?: string; baseTranslation?: string; - translation?: string; }; KeySearchSearchResultModel: { view?: components["schemas"]["KeySearchResultView"]; name: string; /** Format: int64 */ id: number; - namespace?: string; + translation?: string; description?: string; + namespace?: string; baseTranslation?: string; - translation?: string; }; PagedModelKeySearchSearchResultModel: { _embedded?: { @@ -3705,64 +3766,745 @@ export interface components { avatar?: components["schemas"]["Avatar"]; deleted: boolean; }; - ProjectActivityModel: { - /** Format: int64 */ - revisionId: number; - /** Format: int64 */ - timestamp: number; - type: - | "UNKNOWN" - | "SET_TRANSLATION_STATE" - | "SET_TRANSLATIONS" - | "DISMISS_AUTO_TRANSLATED_STATE" - | "SET_OUTDATED_FLAG" - | "TRANSLATION_COMMENT_ADD" - | "TRANSLATION_COMMENT_DELETE" - | "TRANSLATION_COMMENT_EDIT" - | "TRANSLATION_COMMENT_SET_STATE" - | "SCREENSHOT_DELETE" - | "SCREENSHOT_ADD" - | "KEY_TAGS_EDIT" - | "KEY_NAME_EDIT" - | "KEY_DELETE" - | "CREATE_KEY" - | "COMPLEX_EDIT" - | "IMPORT" - | "CREATE_LANGUAGE" - | "EDIT_LANGUAGE" - | "DELETE_LANGUAGE" - | "HARD_DELETE_LANGUAGE" - | "CREATE_PROJECT" - | "EDIT_PROJECT" - | "NAMESPACE_EDIT" - | "BATCH_PRE_TRANSLATE_BY_TM" - | "BATCH_MACHINE_TRANSLATE" - | "AUTO_TRANSLATE" - | "BATCH_CLEAR_TRANSLATIONS" - | "BATCH_COPY_TRANSLATIONS" - | "BATCH_SET_TRANSLATION_STATE" - | "BATCH_TAG_KEYS" - | "BATCH_UNTAG_KEYS" - | "BATCH_SET_KEYS_NAMESPACE" - | "AUTOMATION" - | "CONTENT_DELIVERY_CONFIG_CREATE" - | "CONTENT_DELIVERY_CONFIG_UPDATE" - | "CONTENT_DELIVERY_CONFIG_DELETE" - | "CONTENT_STORAGE_CREATE" - | "CONTENT_STORAGE_UPDATE" - | "CONTENT_STORAGE_DELETE" - | "WEBHOOK_CONFIG_CREATE" - | "WEBHOOK_CONFIG_UPDATE" - | "WEBHOOK_CONFIG_DELETE" - | "COMPLEX_TAG_OPERATION"; - author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: { - [key: string]: components["schemas"]["ModifiedEntityModel"][]; - }; - meta?: { [key: string]: { [key: string]: unknown } }; - counts?: { [key: string]: number }; - params?: { [key: string]: unknown }; - }; + ProjectActivityModel: + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "UNKNOWN"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "SET_TRANSLATION_STATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + Translation?: { + entityClass?: string; + /** Format: int64 */ + entityId?: number; + description?: { [key: string]: { [key: string]: unknown } }; + modifications?: { + text?: { + old?: string; + new?: string; + }; + state?: { + old?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + new?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + }; + auto?: { + old?: boolean; + new?: boolean; + }; + mtProvider?: { + old?: + | "GOOGLE" + | "AWS" + | "DEEPL" + | "AZURE" + | "BAIDU" + | "TOLGEE"; + new?: + | "GOOGLE" + | "AWS" + | "DEEPL" + | "AZURE" + | "BAIDU" + | "TOLGEE"; + }; + outdated?: { + old?: boolean; + new?: boolean; + }; + }; + relations?: { + [ + key: string + ]: components["schemas"]["ExistenceEntityDescription"]; + }; + exists?: boolean; + }; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "SET_TRANSLATIONS"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + Translation?: { + entityClass?: string; + /** Format: int64 */ + entityId?: number; + description?: { [key: string]: { [key: string]: unknown } }; + modifications?: { + text?: { + old?: string; + new?: string; + }; + state?: { + old?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + new?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + }; + auto?: { + old?: boolean; + new?: boolean; + }; + mtProvider?: { + old?: + | "GOOGLE" + | "AWS" + | "DEEPL" + | "AZURE" + | "BAIDU" + | "TOLGEE"; + new?: + | "GOOGLE" + | "AWS" + | "DEEPL" + | "AZURE" + | "BAIDU" + | "TOLGEE"; + }; + outdated?: { + old?: boolean; + new?: boolean; + }; + }; + relations?: { + [ + key: string + ]: components["schemas"]["ExistenceEntityDescription"]; + }; + exists?: boolean; + }; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "DISMISS_AUTO_TRANSLATED_STATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + Translation?: { + entityClass?: string; + /** Format: int64 */ + entityId?: number; + description?: { [key: string]: { [key: string]: unknown } }; + modifications?: { + text?: { + old?: string; + new?: string; + }; + state?: { + old?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + new?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + }; + auto?: { + old?: boolean; + new?: boolean; + }; + mtProvider?: { + old?: + | "GOOGLE" + | "AWS" + | "DEEPL" + | "AZURE" + | "BAIDU" + | "TOLGEE"; + new?: + | "GOOGLE" + | "AWS" + | "DEEPL" + | "AZURE" + | "BAIDU" + | "TOLGEE"; + }; + outdated?: { + old?: boolean; + new?: boolean; + }; + }; + relations?: { + [ + key: string + ]: components["schemas"]["ExistenceEntityDescription"]; + }; + exists?: boolean; + }; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "SET_OUTDATED_FLAG"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "TRANSLATION_COMMENT_ADD"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "TRANSLATION_COMMENT_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "TRANSLATION_COMMENT_EDIT"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "TRANSLATION_COMMENT_SET_STATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "SCREENSHOT_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "SCREENSHOT_ADD"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "KEY_TAGS_EDIT"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "KEY_NAME_EDIT"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "KEY_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "CREATE_KEY"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + Key?: { + entityClass?: string; + /** Format: int64 */ + entityId?: number; + description?: { [key: string]: { [key: string]: unknown } }; + modifications?: { + name?: { + old?: unknown; + new?: string; + }; + isPlural?: { + old?: unknown; + new?: boolean; + }; + pluralArgName?: { + old?: unknown; + new?: string; + }; + namespace?: { + old?: unknown; + new?: { + entityClass: string; + /** Format: int64 */ + entityId: number; + data: { + name?: string; + }; + }; + }; + }; + relations?: { + [ + key: string + ]: components["schemas"]["ExistenceEntityDescription"]; + }; + exists?: boolean; + }; + KeyMeta?: { + entityClass?: string; + /** Format: int64 */ + entityId?: number; + description?: { [key: string]: { [key: string]: unknown } }; + modifications?: { + description?: { + old?: unknown; + new?: string; + }; + custom?: { + old?: unknown; + new?: { [key: string]: { [key: string]: unknown } }; + }; + tags?: { + old?: unknown; + new?: { + entityClass: string; + /** Format: int64 */ + entityId: number; + data: { [key: string]: unknown }; + }; + }; + }; + relations?: { + [ + key: string + ]: components["schemas"]["ExistenceEntityDescription"]; + }; + exists?: boolean; + }; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "COMPLEX_EDIT"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "IMPORT"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "CREATE_LANGUAGE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "EDIT_LANGUAGE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "DELETE_LANGUAGE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "HARD_DELETE_LANGUAGE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "CREATE_PROJECT"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "EDIT_PROJECT"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "NAMESPACE_EDIT"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_PRE_TRANSLATE_BY_TM"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_MACHINE_TRANSLATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "AUTO_TRANSLATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_CLEAR_TRANSLATIONS"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_COPY_TRANSLATIONS"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_SET_TRANSLATION_STATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_TAG_KEYS"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_UNTAG_KEYS"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_SET_KEYS_NAMESPACE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "AUTOMATION"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "CONTENT_DELIVERY_CONFIG_CREATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "CONTENT_DELIVERY_CONFIG_UPDATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "CONTENT_DELIVERY_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "CONTENT_STORAGE_CREATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "CONTENT_STORAGE_UPDATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "CONTENT_STORAGE_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "WEBHOOK_CONFIG_CREATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "WEBHOOK_CONFIG_UPDATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + } + | { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "COMPLEX_TAG_OPERATION"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; PagedModelProjectActivityModel: { _embedded?: { activities?: components["schemas"]["ProjectActivityModel"][]; @@ -4173,15 +4915,15 @@ export interface components { user: components["schemas"]["SimpleUserAccountModel"]; /** Format: int64 */ id: number; - description: string; /** Format: int64 */ createdAt: number; /** Format: int64 */ updatedAt: number; /** Format: int64 */ - expiresAt?: number; - /** Format: int64 */ lastUsedAt?: number; + /** Format: int64 */ + expiresAt?: number; + description: string; }; PagedModelOrganizationModel: { _embedded?: { @@ -4302,6 +5044,44 @@ export interface components { projectsWithDirectPermission: components["schemas"]["SimpleProjectModel"][]; avatar?: components["schemas"]["Avatar"]; }; + SimpleModifiedEntityView: { + entityClass: string; + /** Format: int64 */ + entityId: number; + exists?: boolean; + modifications: { + [key: string]: components["schemas"]["PropertyModification"]; + }; + description?: { [key: string]: { [key: string]: unknown } }; + describingRelations?: { + [key: string]: components["schemas"]["ExistenceEntityDescription"]; + }; + }; + UserNotificationModel: { + /** Format: int64 */ + id: number; + type: + | "ACTIVITY_LANGUAGES_CREATED" + | "ACTIVITY_KEYS_CREATED" + | "ACTIVITY_KEYS_UPDATED" + | "ACTIVITY_KEYS_SCREENSHOTS_UPLOADED" + | "ACTIVITY_SOURCE_STRINGS_UPDATED" + | "ACTIVITY_TRANSLATIONS_UPDATED" + | "ACTIVITY_TRANSLATION_OUTDATED" + | "ACTIVITY_TRANSLATION_REVIEWED" + | "ACTIVITY_TRANSLATION_UNREVIEWED" + | "ACTIVITY_NEW_COMMENTS" + | "ACTIVITY_COMMENTS_MENTION" + | "BATCH_JOB_ERRORED"; + project?: components["schemas"]["SimpleProjectModel"]; + batchJob?: components["schemas"]["BatchJobModel"]; + modifiedEntities?: components["schemas"]["SimpleModifiedEntityView"][]; + unread: boolean; + /** Format: date-time */ + markedDoneAt?: string; + /** Format: date-time */ + lastUpdated: string; + }; ApiKeyWithLanguagesModel: { /** * @deprecated @@ -4310,17 +5090,17 @@ export interface components { permittedLanguageIds?: number[]; /** Format: int64 */ id: number; - projectName: string; - userFullName?: string; - description: string; - username?: string; + scopes: string[]; /** Format: int64 */ projectId: number; - /** Format: int64 */ - expiresAt?: number; + username?: string; /** Format: int64 */ lastUsedAt?: number; - scopes: string[]; + /** Format: int64 */ + expiresAt?: number; + description: string; + projectName: string; + userFullName?: string; }; PagedModelUserAccountModel: { _embedded?: { @@ -4346,82 +5126,774 @@ export interface components { /** @description IDs of keys to delete */ ids: number[]; }; - }; -} - -export interface operations { - /** Returns information about currently authenticated user. */ - getInfo_2: { - responses: { - /** OK */ - 200: { - content: { - "application/json": components["schemas"]["PrivateUserAccountModel"]; - }; - }; - /** Bad Request */ - 400: { - content: { - "application/json": - | components["schemas"]["ErrorResponseTyped"] - | components["schemas"]["ErrorResponseBody"]; - }; - }; - /** Unauthorized */ - 401: { - content: { - "application/json": - | components["schemas"]["ErrorResponseTyped"] - | components["schemas"]["ErrorResponseBody"]; - }; - }; - /** Forbidden */ - 403: { - content: { - "application/json": - | components["schemas"]["ErrorResponseTyped"] - | components["schemas"]["ErrorResponseBody"]; - }; - }; - /** Not Found */ - 404: { - content: { - "application/json": - | components["schemas"]["ErrorResponseTyped"] - | components["schemas"]["ErrorResponseBody"]; - }; - }; + ProjectActivityUnknownModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "UNKNOWN"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; }; - }; - /** Updates current user's profile information. */ - updateUser: { - responses: { - /** OK */ - 200: { - content: { - "application/json": components["schemas"]["PrivateUserAccountModel"]; + ProjectActivitySetTranslationStateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "SET_TRANSLATION_STATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + Translation?: { + entityClass?: string; + /** Format: int64 */ + entityId?: number; + description?: { [key: string]: { [key: string]: unknown } }; + modifications?: { + text?: { + old?: string; + new?: string; + }; + state?: { + old?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + new?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + }; + auto?: { + old?: boolean; + new?: boolean; + }; + mtProvider?: { + old?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE"; + new?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE"; + }; + outdated?: { + old?: boolean; + new?: boolean; + }; + }; + relations?: { + [key: string]: components["schemas"]["ExistenceEntityDescription"]; + }; + exists?: boolean; }; }; - /** Bad Request */ - 400: { - content: { - "application/json": - | components["schemas"]["ErrorResponseTyped"] - | components["schemas"]["ErrorResponseBody"]; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivitySetTranslationsModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "SET_TRANSLATIONS"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + Translation?: { + entityClass?: string; + /** Format: int64 */ + entityId?: number; + description?: { [key: string]: { [key: string]: unknown } }; + modifications?: { + text?: { + old?: string; + new?: string; + }; + state?: { + old?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + new?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + }; + auto?: { + old?: boolean; + new?: boolean; + }; + mtProvider?: { + old?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE"; + new?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE"; + }; + outdated?: { + old?: boolean; + new?: boolean; + }; + }; + relations?: { + [key: string]: components["schemas"]["ExistenceEntityDescription"]; + }; + exists?: boolean; }; }; - /** Unauthorized */ - 401: { - content: { - "application/json": - | components["schemas"]["ErrorResponseTyped"] - | components["schemas"]["ErrorResponseBody"]; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityDismissAutoTranslatedStateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "DISMISS_AUTO_TRANSLATED_STATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + Translation?: { + entityClass?: string; + /** Format: int64 */ + entityId?: number; + description?: { [key: string]: { [key: string]: unknown } }; + modifications?: { + text?: { + old?: string; + new?: string; + }; + state?: { + old?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + new?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + }; + auto?: { + old?: boolean; + new?: boolean; + }; + mtProvider?: { + old?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE"; + new?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE"; + }; + outdated?: { + old?: boolean; + new?: boolean; + }; + }; + relations?: { + [key: string]: components["schemas"]["ExistenceEntityDescription"]; + }; + exists?: boolean; }; }; - /** Forbidden */ - 403: { - content: { - "application/json": + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivitySetOutdatedFlagModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "SET_OUTDATED_FLAG"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityTranslationCommentAddModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "TRANSLATION_COMMENT_ADD"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityTranslationCommentDeleteModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "TRANSLATION_COMMENT_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityTranslationCommentEditModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "TRANSLATION_COMMENT_EDIT"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityTranslationCommentSetStateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "TRANSLATION_COMMENT_SET_STATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityScreenshotDeleteModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "SCREENSHOT_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityScreenshotAddModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "SCREENSHOT_ADD"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityKeyTagsEditModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "KEY_TAGS_EDIT"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityKeyNameEditModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "KEY_NAME_EDIT"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityKeyDeleteModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "KEY_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityCreateKeyModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "CREATE_KEY"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + Key?: { + entityClass?: string; + /** Format: int64 */ + entityId?: number; + description?: { [key: string]: { [key: string]: unknown } }; + modifications?: { + name?: { + old?: unknown; + new?: string; + }; + isPlural?: { + old?: unknown; + new?: boolean; + }; + pluralArgName?: { + old?: unknown; + new?: string; + }; + namespace?: { + old?: unknown; + new?: { + entityClass: string; + /** Format: int64 */ + entityId: number; + data: { + name?: string; + }; + }; + }; + }; + relations?: { + [key: string]: components["schemas"]["ExistenceEntityDescription"]; + }; + exists?: boolean; + }; + KeyMeta?: { + entityClass?: string; + /** Format: int64 */ + entityId?: number; + description?: { [key: string]: { [key: string]: unknown } }; + modifications?: { + description?: { + old?: unknown; + new?: string; + }; + custom?: { + old?: unknown; + new?: { [key: string]: { [key: string]: unknown } }; + }; + tags?: { + old?: unknown; + new?: { + entityClass: string; + /** Format: int64 */ + entityId: number; + data: { [key: string]: unknown }; + }; + }; + }; + relations?: { + [key: string]: components["schemas"]["ExistenceEntityDescription"]; + }; + exists?: boolean; + }; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityComplexEditModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "COMPLEX_EDIT"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityImportModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "IMPORT"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityCreateLanguageModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "CREATE_LANGUAGE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityEditLanguageModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "EDIT_LANGUAGE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityDeleteLanguageModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "DELETE_LANGUAGE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityHardDeleteLanguageModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "HARD_DELETE_LANGUAGE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityCreateProjectModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "CREATE_PROJECT"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityEditProjectModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "EDIT_PROJECT"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityNamespaceEditModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "NAMESPACE_EDIT"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityBatchPreTranslateByTmModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_PRE_TRANSLATE_BY_TM"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityBatchMachineTranslateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_MACHINE_TRANSLATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityAutoTranslateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "AUTO_TRANSLATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityBatchClearTranslationsModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_CLEAR_TRANSLATIONS"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityBatchCopyTranslationsModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_COPY_TRANSLATIONS"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityBatchSetTranslationStateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_SET_TRANSLATION_STATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityBatchTagKeysModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_TAG_KEYS"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityBatchUntagKeysModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_UNTAG_KEYS"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityBatchSetKeysNamespaceModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_SET_KEYS_NAMESPACE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityAutomationModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "AUTOMATION"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityContentDeliveryConfigCreateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "CONTENT_DELIVERY_CONFIG_CREATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityContentDeliveryConfigUpdateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "CONTENT_DELIVERY_CONFIG_UPDATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityContentDeliveryConfigDeleteModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "CONTENT_DELIVERY_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityContentStorageCreateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "CONTENT_STORAGE_CREATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityContentStorageUpdateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "CONTENT_STORAGE_UPDATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityContentStorageDeleteModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "CONTENT_STORAGE_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityWebhookConfigCreateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "WEBHOOK_CONFIG_CREATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityWebhookConfigUpdateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "WEBHOOK_CONFIG_UPDATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityWebhookConfigDeleteModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityComplexTagOperationModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "COMPLEX_TAG_OPERATION"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + }; +} + +export interface operations { + /** Returns information about currently authenticated user. */ + getInfo_2: { + responses: { + /** OK */ + 200: { + content: { + "application/json": components["schemas"]["PrivateUserAccountModel"]; + }; + }; + /** Bad Request */ + 400: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Unauthorized */ + 401: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Forbidden */ + 403: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Not Found */ + 404: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Updates current user's profile information. */ + updateUser: { + responses: { + /** OK */ + 200: { + content: { + "application/json": components["schemas"]["PrivateUserAccountModel"]; + }; + }; + /** Bad Request */ + 400: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Unauthorized */ + 401: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Forbidden */ + 403: { + content: { + "application/json": | components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; }; @@ -8985,6 +10457,237 @@ export interface operations { }; }; }; + getPerProjectPreferences: { + parameters: { + path: { + id: number; + }; + }; + responses: { + /** OK */ + 200: { + content: { + "application/json": components["schemas"]["NotificationPreferencesDto"]; + }; + }; + /** Bad Request */ + 400: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Unauthorized */ + 401: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Forbidden */ + 403: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Not Found */ + 404: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + updatePerProjectPreferences: { + parameters: { + path: { + id: number; + }; + }; + responses: { + /** OK */ + 200: { + content: { + "application/json": components["schemas"]["NotificationPreferencesDto"]; + }; + }; + /** Bad Request */ + 400: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Unauthorized */ + 401: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Forbidden */ + 403: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Not Found */ + 404: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["NotificationPreferencesDto"]; + }; + }; + }; + deletePerProjectPreferences: { + parameters: { + path: { + id: number; + }; + }; + responses: { + /** No Content */ + 204: never; + /** Bad Request */ + 400: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Unauthorized */ + 401: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Forbidden */ + 403: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Not Found */ + 404: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + getGlobalPreferences: { + responses: { + /** OK */ + 200: { + content: { + "application/json": components["schemas"]["NotificationPreferencesDto"]; + }; + }; + /** Bad Request */ + 400: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Unauthorized */ + 401: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Forbidden */ + 403: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Not Found */ + 404: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + updateGlobalPreferences: { + responses: { + /** OK */ + 200: { + content: { + "application/json": components["schemas"]["NotificationPreferencesDto"]; + }; + }; + /** Bad Request */ + 400: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Unauthorized */ + 401: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Forbidden */ + 403: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Not Found */ + 404: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["NotificationPreferencesDto"]; + }; + }; + }; setLicenseKey: { responses: { /** OK */ @@ -11905,7 +13608,328 @@ export interface operations { /** OK */ 200: { content: { - "application/json": components["schemas"]["StreamingResponseBody"]; + "application/json": components["schemas"]["StreamingResponseBody"]; + }; + }; + /** Bad Request */ + 400: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Unauthorized */ + 401: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Forbidden */ + 403: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Not Found */ + 404: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Exports data (post). Useful when exceeding allowed URL size. */ + exportPost: { + parameters: { + path: { + projectId: number; + }; + }; + responses: { + /** OK */ + 200: { + content: { + "application/json": components["schemas"]["StreamingResponseBody"]; + }; + }; + /** Bad Request */ + 400: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Unauthorized */ + 401: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Forbidden */ + 403: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Not Found */ + 404: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["ExportParams"]; + }; + }; + }; + /** Stores a bigMeta for a project */ + store_2: { + parameters: { + path: { + projectId: number; + }; + }; + responses: { + /** OK */ + 200: unknown; + /** Bad Request */ + 400: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Unauthorized */ + 401: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Forbidden */ + 403: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Not Found */ + 404: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["BigMetaDto"]; + }; + }; + }; + /** Returns translation comments of translation */ + getAll_5: { + parameters: { + path: { + translationId: number; + projectId: number; + }; + query: { + /** Zero-based page index (0..N) */ + page?: number; + /** The size of the page to be returned */ + size?: number; + /** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + }; + }; + responses: { + /** OK */ + 200: { + content: { + "application/json": components["schemas"]["PagedModelTranslationCommentModel"]; + }; + }; + /** Bad Request */ + 400: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Unauthorized */ + 401: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Forbidden */ + 403: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Not Found */ + 404: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + create_7: { + parameters: { + path: { + translationId: number; + projectId: number; + }; + }; + responses: { + /** Created */ + 201: { + content: { + "*/*": components["schemas"]["TranslationCommentModel"]; + }; + }; + /** Bad Request */ + 400: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Unauthorized */ + 401: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Forbidden */ + 403: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Not Found */ + 404: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["TranslationCommentDto"]; + }; + }; + }; + /** Creates a translation comment. Empty translation is stored, when not exists. */ + create_9: { + parameters: { + path: { + projectId: number; + }; + }; + responses: { + /** Created */ + 201: { + content: { + "*/*": components["schemas"]["TranslationWithCommentModel"]; + }; + }; + /** Bad Request */ + 400: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Unauthorized */ + 401: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Forbidden */ + 403: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Not Found */ + 404: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["TranslationCommentWithLangKeyDto"]; + }; + }; + }; + /** Suggests machine translations from translation memory. The result is always sorted by similarity, so sorting is not supported. */ + suggestTranslationMemory: { + parameters: { + query: { + /** Zero-based page index (0..N) */ + page?: number; + /** The size of the page to be returned */ + size?: number; + /** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + }; + path: { + projectId: number; + }; + }; + responses: { + /** OK */ + 200: { + content: { + "application/json": components["schemas"]["PagedModelTranslationMemoryItemModel"]; }; }; /** Bad Request */ @@ -11941,9 +13965,14 @@ export interface operations { }; }; }; + requestBody: { + content: { + "application/json": components["schemas"]["SuggestRequestDto"]; + }; + }; }; - /** Exports data (post). Useful when exceeding allowed URL size. */ - exportPost: { + /** Suggests machine translations from enabled services. The results are streamed to the output in ndjson format. If an error occurs when for any service provider used, the error information is returned as a part of the result item, while the response has 200 status code. */ + suggestMachineTranslationsStreaming: { parameters: { path: { projectId: number; @@ -11953,7 +13982,7 @@ export interface operations { /** OK */ 200: { content: { - "application/json": components["schemas"]["StreamingResponseBody"]; + "application/x-ndjson": components["schemas"]["StreamingResponseBody"]; }; }; /** Bad Request */ @@ -11991,12 +14020,12 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["ExportParams"]; + "application/json": components["schemas"]["SuggestRequestDto"]; }; }; }; - /** Stores a bigMeta for a project */ - store_2: { + /** Suggests machine translations from enabled services */ + suggestMachineTranslations: { parameters: { path: { projectId: number; @@ -12004,7 +14033,11 @@ export interface operations { }; responses: { /** OK */ - 200: unknown; + 200: { + content: { + "application/json": components["schemas"]["SuggestResultModel"]; + }; + }; /** Bad Request */ 400: { content: { @@ -12040,15 +14073,13 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["BigMetaDto"]; + "application/json": components["schemas"]["SuggestRequestDto"]; }; }; }; - /** Returns translation comments of translation */ - getAll_5: { + getAll_7: { parameters: { path: { - translationId: number; projectId: number; }; query: { @@ -12064,7 +14095,7 @@ export interface operations { /** OK */ 200: { content: { - "application/json": components["schemas"]["PagedModelTranslationCommentModel"]; + "application/json": components["schemas"]["PagedModelLanguageModel"]; }; }; /** Bad Request */ @@ -12101,18 +14132,17 @@ export interface operations { }; }; }; - create_7: { + createLanguage: { parameters: { path: { - translationId: number; projectId: number; }; }; responses: { - /** Created */ - 201: { + /** OK */ + 200: { content: { - "*/*": components["schemas"]["TranslationCommentModel"]; + "application/json": components["schemas"]["LanguageModel"]; }; }; /** Bad Request */ @@ -12150,22 +14180,22 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["TranslationCommentDto"]; + "application/json": components["schemas"]["LanguageRequest"]; }; }; }; - /** Creates a translation comment. Empty translation is stored, when not exists. */ - create_9: { + getKeyScreenshots_1: { parameters: { path: { + keyId: number; projectId: number; }; }; responses: { - /** Created */ - 201: { + /** OK */ + 200: { content: { - "*/*": components["schemas"]["TranslationWithCommentModel"]; + "application/json": components["schemas"]["CollectionModelScreenshotModel"]; }; }; /** Bad Request */ @@ -12201,32 +14231,19 @@ export interface operations { }; }; }; - requestBody: { - content: { - "application/json": components["schemas"]["TranslationCommentWithLangKeyDto"]; - }; - }; }; - /** Suggests machine translations from translation memory. The result is always sorted by similarity, so sorting is not supported. */ - suggestTranslationMemory: { + uploadScreenshot_1: { parameters: { - query: { - /** Zero-based page index (0..N) */ - page?: number; - /** The size of the page to be returned */ - size?: number; - /** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ - sort?: string[]; - }; path: { + keyId: number; projectId: number; }; }; responses: { - /** OK */ - 200: { + /** Created */ + 201: { content: { - "application/json": components["schemas"]["PagedModelTranslationMemoryItemModel"]; + "*/*": components["schemas"]["ScreenshotModel"]; }; }; /** Bad Request */ @@ -12264,22 +14281,30 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["SuggestRequestDto"]; + "multipart/form-data": { + /** Format: binary */ + screenshot: string; + info?: components["schemas"]["ScreenshotInfoDto"]; + }; }; }; }; - /** Suggests machine translations from enabled services. The results are streamed to the output in ndjson format. If an error occurs when for any service provider used, the error information is returned as a part of the result item, while the response has 200 status code. */ - suggestMachineTranslationsStreaming: { + getAll_9: { parameters: { - path: { - projectId: number; + query: { + /** Zero-based page index (0..N) */ + page?: number; + /** The size of the page to be returned */ + size?: number; + /** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; }; }; responses: { /** OK */ 200: { content: { - "application/x-ndjson": components["schemas"]["StreamingResponseBody"]; + "application/json": components["schemas"]["PagedModelPatModel"]; }; }; /** Bad Request */ @@ -12315,24 +14340,13 @@ export interface operations { }; }; }; - requestBody: { - content: { - "application/json": components["schemas"]["SuggestRequestDto"]; - }; - }; }; - /** Suggests machine translations from enabled services */ - suggestMachineTranslations: { - parameters: { - path: { - projectId: number; - }; - }; + create_11: { responses: { - /** OK */ - 200: { + /** Created */ + 201: { content: { - "application/json": components["schemas"]["SuggestResultModel"]; + "*/*": components["schemas"]["RevealedPatModel"]; }; }; /** Bad Request */ @@ -12370,15 +14384,13 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["SuggestRequestDto"]; + "application/json": components["schemas"]["CreatePatDto"]; }; }; }; - getAll_7: { + /** Returns all organizations, which is current user allowed to view */ + getAll_10: { parameters: { - path: { - projectId: number; - }; query: { /** Zero-based page index (0..N) */ page?: number; @@ -12386,13 +14398,15 @@ export interface operations { size?: number; /** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ sort?: string[]; + filterCurrentUserOwner?: boolean; + search?: string; }; }; responses: { /** OK */ 200: { content: { - "application/json": components["schemas"]["PagedModelLanguageModel"]; + "application/hal+json": components["schemas"]["PagedModelOrganizationModel"]; }; }; /** Bad Request */ @@ -12429,17 +14443,12 @@ export interface operations { }; }; }; - createLanguage: { - parameters: { - path: { - projectId: number; - }; - }; + create_12: { responses: { /** OK */ 200: { content: { - "application/json": components["schemas"]["LanguageModel"]; + "application/json": components["schemas"]["OrganizationModel"]; }; }; /** Bad Request */ @@ -12477,24 +14486,66 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["LanguageRequest"]; + "application/json": components["schemas"]["OrganizationDto"]; + }; + }; + }; + /** + * This endpoint allows the owner of an organization to connect a Slack workspace to their organization. + * Checks if the Slack integration feature is enabled for the organization and proceeds with the connection. + */ + connectWorkspace: { + parameters: { + path: { + organizationId: number; + }; + }; + responses: { + /** OK */ + 200: unknown; + /** Bad Request */ + 400: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Unauthorized */ + 401: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Forbidden */ + 403: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Not Found */ + 404: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["ConnectToSlackDto"]; }; }; }; - getKeyScreenshots_1: { - parameters: { - path: { - keyId: number; - projectId: number; - }; - }; + unmarkNotificationsAsDone: { responses: { - /** OK */ - 200: { - content: { - "application/json": components["schemas"]["CollectionModelScreenshotModel"]; - }; - }; + /** No Content */ + 204: never; /** Bad Request */ 400: { content: { @@ -12528,19 +14579,23 @@ export interface operations { }; }; }; + requestBody: { + content: { + "application/json": number[]; + }; + }; }; - uploadScreenshot_1: { + subscribeToProject: { parameters: { path: { - keyId: number; - projectId: number; + id: number; }; }; responses: { - /** Created */ - 201: { + /** OK */ + 200: { content: { - "*/*": components["schemas"]["ScreenshotModel"]; + "application/json": string; }; }; /** Bad Request */ @@ -12576,34 +14631,11 @@ export interface operations { }; }; }; - requestBody: { - content: { - "multipart/form-data": { - /** Format: binary */ - screenshot: string; - info?: components["schemas"]["ScreenshotInfoDto"]; - }; - }; - }; }; - getAll_9: { - parameters: { - query: { - /** Zero-based page index (0..N) */ - page?: number; - /** The size of the page to be returned */ - size?: number; - /** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ - sort?: string[]; - }; - }; + markNotificationsAsUnread: { responses: { - /** OK */ - 200: { - content: { - "application/json": components["schemas"]["PagedModelPatModel"]; - }; - }; + /** No Content */ + 204: never; /** Bad Request */ 400: { content: { @@ -12637,15 +14669,16 @@ export interface operations { }; }; }; + requestBody: { + content: { + "application/json": number[]; + }; + }; }; - create_11: { + markNotificationsAsRead: { responses: { - /** Created */ - 201: { - content: { - "*/*": components["schemas"]["RevealedPatModel"]; - }; - }; + /** No Content */ + 204: never; /** Bad Request */ 400: { content: { @@ -12681,31 +14714,14 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["CreatePatDto"]; + "application/json": number[]; }; }; }; - /** Returns all organizations, which is current user allowed to view */ - getAll_10: { - parameters: { - query: { - /** Zero-based page index (0..N) */ - page?: number; - /** The size of the page to be returned */ - size?: number; - /** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ - sort?: string[]; - filterCurrentUserOwner?: boolean; - search?: string; - }; - }; + markAllNotificationsAsRead: { responses: { - /** OK */ - 200: { - content: { - "application/hal+json": components["schemas"]["PagedModelOrganizationModel"]; - }; - }; + /** No Content */ + 204: never; /** Bad Request */ 400: { content: { @@ -12740,14 +14756,10 @@ export interface operations { }; }; }; - create_12: { + markNotificationsAsDone: { responses: { - /** OK */ - 200: { - content: { - "application/json": components["schemas"]["OrganizationModel"]; - }; - }; + /** No Content */ + 204: never; /** Bad Request */ 400: { content: { @@ -12783,23 +14795,14 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["OrganizationDto"]; + "application/json": number[]; }; }; }; - /** - * This endpoint allows the owner of an organization to connect a Slack workspace to their organization. - * Checks if the Slack integration feature is enabled for the organization and proceeds with the connection. - */ - connectWorkspace: { - parameters: { - path: { - organizationId: number; - }; - }; + markAllNotificationsAsDone: { responses: { - /** OK */ - 200: unknown; + /** No Content */ + 204: never; /** Bad Request */ 400: { content: { @@ -12833,11 +14836,6 @@ export interface operations { }; }; }; - requestBody: { - content: { - "application/json": components["schemas"]["ConnectToSlackDto"]; - }; - }; }; upload: { responses: { @@ -14299,6 +16297,62 @@ export interface operations { }; }; }; + /** This endpoints returns the activity grouped by time windows so it's easier to read on the frontend. */ + getActivityGroups: { + parameters: { + query: { + /** Zero-based page index (0..N) */ + page?: number; + /** The size of the page to be returned */ + size?: number; + /** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + }; + path: { + projectId: number; + }; + }; + responses: { + /** OK */ + 200: { + content: { + "application/hal+json": components["schemas"]["PagedModelProjectActivityModel"]; + }; + }; + /** Bad Request */ + 400: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Unauthorized */ + 401: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Forbidden */ + 403: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Not Found */ + 404: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; getActivity: { parameters: { query: { @@ -16346,6 +18400,103 @@ export interface operations { }; }; }; + getNotifications: { + parameters: { + query: { + status?: ("UNREAD" | "READ" | "DONE")[]; + /** Zero-based page index (0..N) */ + page?: number; + /** The size of the page to be returned */ + size?: number; + /** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + }; + }; + responses: { + /** OK */ + 200: { + content: { + "application/json": components["schemas"]["UserNotificationModel"][]; + }; + }; + /** Bad Request */ + 400: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Unauthorized */ + 401: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Forbidden */ + 403: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Not Found */ + 404: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + getAllPreferences: { + responses: { + /** OK */ + 200: { + content: { + "application/json": { + [key: string]: components["schemas"]["NotificationPreferencesDto"]; + }; + }; + }; + /** Bad Request */ + 400: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Unauthorized */ + 401: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Forbidden */ + 403: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Not Found */ + 404: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; acceptInvitation: { parameters: { path: { From 80b59d4259107ccc9da955cda01349b71ddc72fe Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Thu, 22 Aug 2024 17:41:31 +0200 Subject: [PATCH 40/44] feat: "Create Key" group with items --- .../controllers/ProjectActivityController.kt | 15 +- .../ProjectActivityGroupItemsController.kt | 49 + .../hateoas/activity/ActivityGroupModel.kt | 2 +- .../activity/ActivityGroupModelAssembler.kt | 16 +- .../kotlin/io/tolgee/hateoas/key/KeyModel.kt | 22 +- .../io/tolgee/hateoas/key/KeyWithDataModel.kt | 5 +- .../openApi/OpenApiGroupBuilder.kt | 9 +- .../activity/ActivityGroupModelEnhancer.kt | 116 + .../activity/ModificationsSchemaGenerator.kt | 22 +- .../activity/ProjectActivityModelEnhancer.kt | 7 +- .../configuration/openApi/activity/tools.kt | 20 + .../activity/RootActivityProviderTest.kt | 4 +- .../groups/ActivityGroupsCreationTest.kt | 16 +- .../ModificationSchemaGeneratorTest.kt | 17 - backend/data/build.gradle | 1 + .../io/tolgee/activity/data/ActivityType.kt | 2 +- .../activity/groups/ActivityGroupService.kt | 6 +- .../activity/groups/ActivityGroupType.kt | 349 +- .../tolgee/activity/groups/ActivityGrouper.kt | 63 +- .../activity/groups/ActivityGroupsProvider.kt | 156 +- .../GroupEntityModificationDefinition.kt | 14 - .../activity/groups/GroupModelProvider.kt | 12 +- .../ActivityGroupLanguageModel.kt} | 6 +- .../groups/data/ModifiedEntityView.kt | 26 + .../groups/dataProviders/CountsProvider.kt | 60 + .../groups/dataProviders/GroupDataProvider.kt | 55 + .../RelevantModifiedEntitiesProvider.kt | 91 + .../matchers/modifiedEntity/DefaultMatcher.kt | 126 + .../modifiedEntity/ModifiedEntityMatcher.kt | 34 + .../matchers/modifiedEntity/SqlContext.kt | 13 + .../matchers/modifiedEntity/StoringContext.kt | 10 + .../createProject/CreateProjectGroupModel.kt | 4 +- .../CreateProjectGroupModelProvider.kt | 104 +- .../keyCreate/CreateKeyGroupItemModel.kt | 22 + .../keyCreate/CreateKeyGroupModel.kt | 5 + .../keyCreate/CreateKeyGroupModelProvider.kt | 53 + .../rootActivity/ChildItemsProvider.kt | 14 +- .../rootActivity/RootActivityProvider.kt | 13 +- .../rootActivity/RootItemsProvider.kt | 98 +- .../main/kotlin/io/tolgee/api/IKeyModel.kt | 23 + .../dtos/queryResults/ActivityGroupView.kt | 7 +- .../dtos/request/ActivityGroupFilters.kt | 9 + .../tolgee/dtos/request/key/CreateKeyDto.kt | 3 +- .../model/activity/ActivityModifiedEntity.kt | 2 +- .../main/kotlin/io/tolgee/sharedDocs/Key.kt | 6 + .../activity/groups/ActivityGroupItem.tsx | 20 + .../ActivityGroupMentionedLanguages.tsx | 27 + .../CollapsibleActivityGroup.tsx | 24 + .../CreateKeysActivityGroup.tsx | 69 + .../CreateProjectActivityGroup.tsx | 21 + webapp/src/component/activity/types.tsx | 2 +- .../languages/LanguageIconWithTooltip.tsx | 20 + webapp/src/constants/links.tsx | 2 +- webapp/src/service/apiSchema.generated.ts | 4217 +++++++++++++---- webapp/src/views/projects/ActivityView.tsx | 31 + webapp/src/views/projects/ProjectRouter.tsx | 4 + 56 files changed, 4684 insertions(+), 1460 deletions(-) create mode 100644 backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectActivityGroupItemsController.kt create mode 100644 backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/ActivityGroupModelEnhancer.kt create mode 100644 backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/tools.kt delete mode 100644 backend/app/src/test/kotlin/io/tolgee/activity/openApi/ModificationSchemaGeneratorTest.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/GroupEntityModificationDefinition.kt rename backend/data/src/main/kotlin/io/tolgee/activity/groups/{viewProviders/createProject/LanguageModel.kt => baseModels/ActivityGroupLanguageModel.kt} (60%) create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/data/ModifiedEntityView.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/CountsProvider.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/GroupDataProvider.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/RelevantModifiedEntitiesProvider.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/DefaultMatcher.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/ModifiedEntityMatcher.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/SqlContext.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/StoringContext.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupItemModel.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupModel.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupModelProvider.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/api/IKeyModel.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/dtos/request/ActivityGroupFilters.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/sharedDocs/Key.kt create mode 100644 webapp/src/component/activity/groups/ActivityGroupItem.tsx create mode 100644 webapp/src/component/activity/groups/common/ActivityGroupMentionedLanguages.tsx create mode 100644 webapp/src/component/activity/groups/groupTypeComponents/CollapsibleActivityGroup.tsx create mode 100644 webapp/src/component/activity/groups/groupTypeComponents/CreateKeysActivityGroup.tsx create mode 100644 webapp/src/component/activity/groups/groupTypeComponents/CreateProjectActivityGroup.tsx create mode 100644 webapp/src/component/languages/LanguageIconWithTooltip.tsx create mode 100644 webapp/src/views/projects/ActivityView.tsx diff --git a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectActivityController.kt b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectActivityController.kt index f1fcf04b29..01e2ea196f 100644 --- a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectActivityController.kt +++ b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectActivityController.kt @@ -11,6 +11,7 @@ import io.swagger.v3.oas.annotations.tags.Tag import io.tolgee.activity.ActivityService import io.tolgee.activity.groups.ActivityGroupService import io.tolgee.dtos.queryResults.ActivityGroupView +import io.tolgee.dtos.request.ActivityGroupFilters import io.tolgee.exceptions.NotFoundException import io.tolgee.hateoas.activity.ActivityGroupModel import io.tolgee.hateoas.activity.ActivityGroupModelAssembler @@ -35,6 +36,7 @@ import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping @Suppress("MVCPathVariableInspection", "SpringJavaInjectionPointsAutowiringInspection") @RestController @@ -50,8 +52,9 @@ class ProjectActivityController( private val modifiedEntityModelAssembler: ModifiedEntityModelAssembler, private val activityGroupService: ActivityGroupService, private val groupPagedResourcesAssembler: PagedResourcesAssembler, - private val groupModelAssembler: ActivityGroupModelAssembler - ) { + private val groupModelAssembler: ActivityGroupModelAssembler, + private val requestMappingHandlerMapping: RequestMappingHandlerMapping, +) { @Operation(summary = "Get project activity") @GetMapping("", produces = [MediaTypes.HAL_JSON_VALUE]) @RequiresProjectPermissions([ Scope.ACTIVITY_VIEW ]) @@ -108,8 +111,14 @@ class ProjectActivityController( @AllowApiAccess fun getActivityGroups( @ParameterObject pageable: Pageable, + @ParameterObject activityGroupFilters: ActivityGroupFilters, ): PagedModel { - val views = activityGroupService.getProjectActivityGroups(projectId = projectHolder.project.id, pageable) + val views = + activityGroupService.getProjectActivityGroups( + projectId = projectHolder.project.id, + pageable, + activityGroupFilters, + ) return groupPagedResourcesAssembler.toModel(views, groupModelAssembler) } } diff --git a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectActivityGroupItemsController.kt b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectActivityGroupItemsController.kt new file mode 100644 index 0000000000..3a6d6a6a0d --- /dev/null +++ b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectActivityGroupItemsController.kt @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020. Tolgee + */ + +package io.tolgee.api.v2.controllers + +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag +import io.tolgee.activity.groups.viewProviders.keyCreate.CreateKeyGroupItemModel +import io.tolgee.activity.groups.viewProviders.keyCreate.CreateKeyGroupModelProvider +import io.tolgee.model.enums.Scope +import io.tolgee.security.authentication.AllowApiAccess +import io.tolgee.security.authorization.RequiresProjectPermissions +import org.springdoc.core.annotations.ParameterObject +import org.springframework.data.domain.Pageable +import org.springframework.hateoas.MediaTypes +import org.springframework.hateoas.PagedModel +import org.springframework.hateoas.PagedModel.PageMetadata +import org.springframework.web.bind.annotation.CrossOrigin +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@Suppress("MVCPathVariableInspection") +@RestController +@CrossOrigin(origins = ["*"]) +@RequestMapping(value = ["/v2/projects/{projectId}/activity/group-items", "/v2/projects/activity/group-items"]) +@Tag(name = "Activity Groups") +class ProjectActivityGroupItemsController( + private val createKeyGroupModelProvider: CreateKeyGroupModelProvider, +) { + @Operation( + summary = "Get CREATE_KEY group items", + ) + @GetMapping("/create-key/{groupId}", produces = [MediaTypes.HAL_JSON_VALUE]) + @RequiresProjectPermissions([Scope.ACTIVITY_VIEW]) + @AllowApiAccess + fun getCreateKeyItems( + @ParameterObject pageable: Pageable, + @PathVariable groupId: Long, + ): PagedModel { + val data = createKeyGroupModelProvider.provideItemModel(groupId, pageable) + return PagedModel.of( + data.content, + PageMetadata(data.pageable.pageSize.toLong(), data.pageable.pageNumber.toLong(), data.totalElements), + ) + } +} diff --git a/backend/api/src/main/kotlin/io/tolgee/hateoas/activity/ActivityGroupModel.kt b/backend/api/src/main/kotlin/io/tolgee/hateoas/activity/ActivityGroupModel.kt index d314254b19..e509ec623a 100644 --- a/backend/api/src/main/kotlin/io/tolgee/hateoas/activity/ActivityGroupModel.kt +++ b/backend/api/src/main/kotlin/io/tolgee/hateoas/activity/ActivityGroupModel.kt @@ -13,6 +13,6 @@ class ActivityGroupModel( val timestamp: Long, val type: ActivityGroupType, val author: SimpleUserAccountModel?, - val counts: Map?, val data: Any?, + var mentionedLanguageIds: List, ) : RepresentationModel(), Serializable diff --git a/backend/api/src/main/kotlin/io/tolgee/hateoas/activity/ActivityGroupModelAssembler.kt b/backend/api/src/main/kotlin/io/tolgee/hateoas/activity/ActivityGroupModelAssembler.kt index 9e7d924a9e..d5da300c7b 100644 --- a/backend/api/src/main/kotlin/io/tolgee/hateoas/activity/ActivityGroupModelAssembler.kt +++ b/backend/api/src/main/kotlin/io/tolgee/hateoas/activity/ActivityGroupModelAssembler.kt @@ -1,29 +1,25 @@ package io.tolgee.hateoas.activity -import io.tolgee.api.IProjectActivityModel -import io.tolgee.api.IProjectActivityModelAssembler import io.tolgee.dtos.queryResults.ActivityGroupView -import io.tolgee.hateoas.userAccount.SimpleUserAccountModel import io.tolgee.hateoas.userAccount.SimpleUserAccountModelAssembler -import io.tolgee.model.views.activity.ProjectActivityView -import io.tolgee.service.AvatarService import org.springframework.hateoas.server.RepresentationModelAssembler import org.springframework.stereotype.Component @Component class ActivityGroupModelAssembler( - private val simpleUserAccountModelAssembler: SimpleUserAccountModelAssembler + private val simpleUserAccountModelAssembler: SimpleUserAccountModelAssembler, ) : RepresentationModelAssembler { override fun toModel(view: ActivityGroupView): ActivityGroupModel { return ActivityGroupModel( id = view.id, timestamp = view.timestamp.time, type = view.type, - author = simpleUserAccountModelAssembler.toModel( - view.author - ), - counts = view.counts, + author = + simpleUserAccountModelAssembler.toModel( + view.author, + ), data = view.data, + mentionedLanguageIds = view.mentionedLanguageIds, ) } } diff --git a/backend/api/src/main/kotlin/io/tolgee/hateoas/key/KeyModel.kt b/backend/api/src/main/kotlin/io/tolgee/hateoas/key/KeyModel.kt index b2ec32d22f..e8774960b4 100644 --- a/backend/api/src/main/kotlin/io/tolgee/hateoas/key/KeyModel.kt +++ b/backend/api/src/main/kotlin/io/tolgee/hateoas/key/KeyModel.kt @@ -1,6 +1,6 @@ package io.tolgee.hateoas.key -import io.swagger.v3.oas.annotations.media.Schema +import io.tolgee.api.IKeyModel import org.springframework.hateoas.RepresentationModel import org.springframework.hateoas.server.core.Relation import java.io.Serializable @@ -8,17 +8,9 @@ import java.io.Serializable @Suppress("unused") @Relation(collectionRelation = "keys", itemRelation = "key") open class KeyModel( - @Schema(description = "Id of key record") - val id: Long, - @Schema(description = "Name of key", example = "this_is_super_key") - val name: String, - @Schema(description = "Namespace of key", example = "homepage") - val namespace: String?, - @Schema( - description = "Description of key", - example = "This key is used on homepage. It's a label of sign up button.", - ) - val description: String?, - @Schema(description = "Custom values of the key") - val custom: Map?, -) : RepresentationModel(), Serializable + override val id: Long, + override val name: String, + override val namespace: String?, + override val description: String?, + override val custom: Map?, +) : RepresentationModel(), Serializable, IKeyModel diff --git a/backend/api/src/main/kotlin/io/tolgee/hateoas/key/KeyWithDataModel.kt b/backend/api/src/main/kotlin/io/tolgee/hateoas/key/KeyWithDataModel.kt index b23671cfbc..875b95e099 100644 --- a/backend/api/src/main/kotlin/io/tolgee/hateoas/key/KeyWithDataModel.kt +++ b/backend/api/src/main/kotlin/io/tolgee/hateoas/key/KeyWithDataModel.kt @@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema import io.tolgee.api.v2.hateoas.invitation.TagModel import io.tolgee.hateoas.screenshot.ScreenshotModel import io.tolgee.hateoas.translations.TranslationModel +import io.tolgee.sharedDocs.Key import org.springframework.hateoas.RepresentationModel import org.springframework.hateoas.server.core.Relation import java.io.Serializable @@ -31,9 +32,9 @@ open class KeyWithDataModel( val tags: Set, @Schema(description = "Screenshots of the key") val screenshots: List, - @Schema(description = "If key is pluralized. If it will be reflected in the editor") + @Schema(description = Key.IS_PLURAL_FIELD) val isPlural: Boolean, - @Schema(description = "The argument name for the plural") + @Schema(description = Key.PLURAL_ARG_NAME_FIELD) val pluralArgName: String?, @Schema(description = "Custom values of the key") val custom: Map, diff --git a/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/OpenApiGroupBuilder.kt b/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/OpenApiGroupBuilder.kt index 6bd721bfb4..2cd2e69a6d 100644 --- a/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/OpenApiGroupBuilder.kt +++ b/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/OpenApiGroupBuilder.kt @@ -3,6 +3,7 @@ package io.tolgee.configuration.openApi import io.swagger.v3.oas.models.Operation import io.swagger.v3.oas.models.PathItem import io.swagger.v3.oas.models.Paths +import io.tolgee.configuration.openApi.activity.ActivityGroupModelEnhancer import io.tolgee.configuration.openApi.activity.ProjectActivityModelEnhancer import io.tolgee.openApiDocs.OpenApiCloudExtension import io.tolgee.openApiDocs.OpenApiEeExtension @@ -38,19 +39,17 @@ class OpenApiGroupBuilder( addExtensions() - cleanUnusedModels() - updateActivitySchema() + cleanUnusedModels() + return@lazy builder.build() } - // todo: Remove this! private fun updateActivitySchema() { -// val keySchema = ModificationsSchemaGenerator().getModificationSchema(Key::class) builder.addOpenApiCustomizer { ProjectActivityModelEnhancer(it).enhance() -// it.schema("KeyModifiedEntity", keySchema) + ActivityGroupModelEnhancer(it).enhance() } } diff --git a/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/ActivityGroupModelEnhancer.kt b/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/ActivityGroupModelEnhancer.kt new file mode 100644 index 0000000000..a3bc50a8f7 --- /dev/null +++ b/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/ActivityGroupModelEnhancer.kt @@ -0,0 +1,116 @@ +package io.tolgee.configuration.openApi.activity + +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import io.swagger.v3.oas.models.OpenAPI +import io.swagger.v3.oas.models.media.Schema +import io.tolgee.activity.groups.ActivityGroupType +import org.apache.commons.text.CaseUtils + +class ActivityGroupModelEnhancer( + private val openApi: OpenAPI, +) { + private val baseSchema = + openApi.components.schemas["ActivityGroupModel"] + ?: throw IllegalStateException("ProjectActivityModel schema not found") + + private val baseProperties = baseSchema.properties + + private val baseType = baseSchema.type + + private val newRequired = baseSchema.required.toMutableList() + + fun enhance() { + baseSchema.required = null + baseSchema.properties = null + baseSchema.type = null + baseSchema.oneOf = generateSchemas() + } + + private fun generateSchemas(): MutableList> { + return ActivityGroupType.entries.map { + val schemaName = it.getSchemaName() + Schema().apply { + name = schemaName + properties = getPropertiesForActivitySchema(it) + type = baseType + required = newRequired + } + }.toMutableList().also { schemas -> + openApi.components.schemas.putAll(schemas.associateBy { it.name }) + } + } + + private fun getPropertiesForActivitySchema(type: ActivityGroupType): MutableMap> { + val newProperties = baseProperties.toMutableMap() + newProperties["type"] = getNewTypeProperty(newProperties, type) +// adjustCountsSchema(newProperties, type) + adjustDataSchema(type, newProperties) + return newProperties + } + +// private fun adjustCountsSchema( +// newProperties: MutableMap>, +// type: ActivityGroupType +// ) { +// val countPropertyType = +// newProperties["counts"]?.additionalProperties as? Schema<*> +// ?: throw IllegalStateException("Counts property not found") +// newProperties["counts"] = Schema().also { schema -> +// schema.type = "object" +// schema.properties = +// type.modifications.filter { it.countInView }.also { +// if (it.isNotEmpty()) { +// newRequired.add("counts") +// } +// }.associate { +// val className = it.entityClass.simpleName!! +// schema.addToRequired(className) +// className to countPropertyType +// } +// } +// } + + private fun Schema.addToRequired(className: String) { + if (required == null) { + required = mutableListOf(className) + return + } + required.add(className) + } + + private fun adjustDataSchema( + type: ActivityGroupType, + newProperties: MutableMap>, + ) { + val dataModel = getDataSchema(type) + if (dataModel != null) { + newProperties["data"] = dataModel + } else { + newProperties.remove("data") + } + } + + private fun getDataSchema(type: ActivityGroupType): Schema<*>? { + val modelType = type.getProvidingModelTypes()?.first + return modelType?.let { getEntitySchema(openApi, it) } + } + + private fun getNewTypeProperty( + properties: Map?>, + activityType: ActivityGroupType, + ): Schema<*> { + val oldTypeProperty = properties["type"] ?: throw IllegalStateException("Type property not found") + val newType = oldTypeProperty.clone() + @Suppress("TYPE_MISMATCH_WARNING") + newType.enum = newType.enum.filter { it == activityType.name } + return newType + } + + fun Schema<*>.clone(): Schema<*> { + val objectMapper = jacksonObjectMapper() + return objectMapper.readValue(objectMapper.writeValueAsString(this), Schema::class.java) + } + + private fun ActivityGroupType.getSchemaName() = + "ActivityGroup" + CaseUtils.toCamelCase(this.name, true, '_') + "Model" +} diff --git a/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/ModificationsSchemaGenerator.kt b/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/ModificationsSchemaGenerator.kt index 718c5748eb..94bc3fead2 100644 --- a/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/ModificationsSchemaGenerator.kt +++ b/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/ModificationsSchemaGenerator.kt @@ -1,7 +1,6 @@ package io.tolgee.configuration.openApi.activity -import io.swagger.v3.core.converter.AnnotatedType -import io.swagger.v3.core.converter.ModelConverters +import io.swagger.v3.oas.models.OpenAPI import io.swagger.v3.oas.models.media.Schema import io.tolgee.activity.annotation.ActivityDescribingProp import io.tolgee.activity.annotation.ActivityLoggedProp @@ -14,12 +13,14 @@ import kotlin.reflect.full.findAnnotation import kotlin.reflect.full.isSubclassOf import kotlin.reflect.full.memberProperties -class ModificationsSchemaGenerator { +class ModificationsSchemaGenerator( + private val openAPI: OpenAPI, +) { fun getModificationSchema( entityClass: KClass<*>, definition: EntityModificationTypeDefinition<*>, ): Schema<*> { - val schema = getEntitySchema(entityClass) + val schema = getEntitySchema(openAPI, entityClass) schema.required = emptyList() val properties = getProperties(entityClass, schema) @@ -50,7 +51,7 @@ class ModificationsSchemaGenerator { ): Map> { val loggedProps = getAllLoggedProps(entityClass) val simplePropNames = loggedProps.getSimpleProps().map { it.name } - val schemaSimpleProps = schema.properties.filterKeys { it in simplePropNames } + val schemaSimpleProps = schema.properties?.filterKeys { it in simplePropNames } ?: emptyMap() val singlePropChangeMap = schemaSimpleProps.map { (name, prop) -> @@ -68,10 +69,10 @@ class ModificationsSchemaGenerator { private fun getModificationSchemaForComplexProp(it: KClass<*>): Schema<*> { val describingProps = it.getDescriptionProps().map { it.name } - val entitySchema = getEntitySchema(it) + val entitySchema = getEntitySchema(openAPI, it) val schemaDescribingProps = entitySchema.properties?.filterKeys { propertyName -> propertyName in describingProps } - descriptionSchema.properties["data"]?.let { dataProp -> + descriptionSchema.properties?.get("data")?.let { dataProp -> dataProp.properties = schemaDescribingProps dataProp.additionalProperties = null } @@ -86,11 +87,6 @@ class ModificationsSchemaGenerator { return changeSchema } - private fun getEntitySchema(entityClass: KClass<*>): Schema<*> = - ModelConverters.getInstance() - .readAllAsResolvedSchema(AnnotatedType(entityClass.java)) - .schema ?: Schema() - private fun getAllLoggedProps(entityClass: KClass<*>): List> { return entityClass.memberProperties .filter { it.findAnnotation() != null } @@ -118,7 +114,7 @@ class ModificationsSchemaGenerator { } private val descriptionSchema by lazy { - getEntitySchema(EntityDescription::class) + getEntitySchema(openAPI, EntityDescription::class) } private fun KClassifier?.isSimpleType(): Boolean { diff --git a/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/ProjectActivityModelEnhancer.kt b/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/ProjectActivityModelEnhancer.kt index b256290fa5..77318ec9a4 100644 --- a/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/ProjectActivityModelEnhancer.kt +++ b/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/ProjectActivityModelEnhancer.kt @@ -28,11 +28,10 @@ class ProjectActivityModelEnhancer( baseSchema.required = null baseSchema.properties = null baseSchema.type = null - baseSchema.oneOf = generateSchemas() } - private fun generateSchemas(): MutableList>? { + private fun generateSchemas(): MutableList> { return ActivityType.entries.map { val schemaName = it.getSchemaName() Schema().apply { @@ -57,7 +56,7 @@ class ProjectActivityModelEnhancer( val properties = activityType.typeDefinitions?.map { (entityClass, definition) -> val schema = activityType.createModifiedEntityModel(entityClass) - schema.properties["modifications"] = ModificationsSchemaGenerator().getModificationSchema(entityClass, definition) + schema.properties["modifications"] = ModificationsSchemaGenerator(openApi).getModificationSchema(entityClass, definition) entityClass.simpleName to schema }?.toMap() @@ -83,7 +82,7 @@ class ProjectActivityModelEnhancer( return objectMapper.readValue(objectMapper.writeValueAsString(this), Schema::class.java) } - fun ActivityType.createModifiedEntityModel(entityClass: KClass<*>): Schema<*> { + private fun ActivityType.createModifiedEntityModel(entityClass: KClass<*>): Schema<*> { return Schema().apply { name = this@createModifiedEntityModel.getModifiedEntitySchemaName(entityClass) properties = modifiedEntityModel.properties.toMutableMap() diff --git a/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/tools.kt b/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/tools.kt new file mode 100644 index 0000000000..b083ec1beb --- /dev/null +++ b/backend/app/src/main/kotlin/io/tolgee/configuration/openApi/activity/tools.kt @@ -0,0 +1,20 @@ +package io.tolgee.configuration.openApi.activity + +import io.swagger.v3.core.converter.AnnotatedType +import io.swagger.v3.core.converter.ModelConverters +import io.swagger.v3.oas.models.OpenAPI +import io.swagger.v3.oas.models.media.Schema +import kotlin.reflect.KClass + +fun getEntitySchema( + openApi: OpenAPI, + entityClass: KClass<*>, +): Schema<*> { + val resolved = + ModelConverters.getInstance() + .readAllAsResolvedSchema(AnnotatedType(entityClass.java)) + + resolved.referencedSchemas.forEach(openApi.components.schemas::putIfAbsent) + + return resolved.schema ?: Schema() +} diff --git a/backend/app/src/test/kotlin/io/tolgee/activity/RootActivityProviderTest.kt b/backend/app/src/test/kotlin/io/tolgee/activity/RootActivityProviderTest.kt index 94443bd329..af6548bac1 100644 --- a/backend/app/src/test/kotlin/io/tolgee/activity/RootActivityProviderTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/activity/RootActivityProviderTest.kt @@ -12,11 +12,11 @@ class RootActivityProviderTest : ProjectAuthControllerTest("/v2/projects/") { @Test fun `returns rooted activity`() { importData() - val latestRevisionId = getLatestRevisionId() + val latestRevisionId = getLatestRevisionId()!! val items = RootActivityProvider( applicationContext, - latestRevisionId!!, + listOf(latestRevisionId), KeyActivityTreeDefinitionItem, Pageable.ofSize(100), ).provide() diff --git a/backend/app/src/test/kotlin/io/tolgee/activity/groups/ActivityGroupsCreationTest.kt b/backend/app/src/test/kotlin/io/tolgee/activity/groups/ActivityGroupsCreationTest.kt index 4d6f1764de..583b06cc4e 100644 --- a/backend/app/src/test/kotlin/io/tolgee/activity/groups/ActivityGroupsCreationTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/activity/groups/ActivityGroupsCreationTest.kt @@ -9,6 +9,7 @@ import io.tolgee.fixtures.andIsOk import io.tolgee.model.activity.ActivityGroup import io.tolgee.model.activity.ActivityModifiedEntity import io.tolgee.model.activity.ActivityRevision +import io.tolgee.model.enums.AssignableTranslationState import io.tolgee.model.key.Key import io.tolgee.model.translation.Translation import io.tolgee.testing.annotations.ProjectJWTAuthTestMethod @@ -18,7 +19,6 @@ import org.junit.jupiter.api.Test import org.mockito.Mockito import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.mock.mockito.MockBean -import org.springframework.data.domain.Pageable import java.time.Duration class ActivityGroupsCreationTest : ProjectAuthControllerTest("/v2/projects/") { @@ -75,22 +75,16 @@ class ActivityGroupsCreationTest : ProjectAuthControllerTest("/v2/projects/") { description = "Changed!", tags = listOf("tag1", "tag2"), translations = mapOf(testData.englishLanguage.tag to "Test"), + states = mapOf(testData.englishLanguage.tag to AssignableTranslationState.REVIEWED), ), ).andIsOk assertGroupsForActivity( - ActivityGroupType.KEY_NAME_EDIT, - ActivityGroupType.KEY_TAGS_EDIT, + ActivityGroupType.EDIT_KEY_NAME, + ActivityGroupType.EDIT_KEY_TAGS, ActivityGroupType.SET_TRANSLATIONS, + ActivityGroupType.REVIEW, ) - - val groups = - activityGroupService.getProjectActivityGroups( - projectId = testData.project.id, - pageable = Pageable.ofSize(10), - ) - - groups } private fun assertItStopsGroupingDueToAge() { diff --git a/backend/app/src/test/kotlin/io/tolgee/activity/openApi/ModificationSchemaGeneratorTest.kt b/backend/app/src/test/kotlin/io/tolgee/activity/openApi/ModificationSchemaGeneratorTest.kt deleted file mode 100644 index 2fbebdba28..0000000000 --- a/backend/app/src/test/kotlin/io/tolgee/activity/openApi/ModificationSchemaGeneratorTest.kt +++ /dev/null @@ -1,17 +0,0 @@ -package io.tolgee.activity.openApi - -import io.tolgee.activity.data.ActivityType -import io.tolgee.configuration.openApi.activity.ModificationsSchemaGenerator -import io.tolgee.model.key.Key -import org.junit.jupiter.api.Test - -class ModificationSchemaGeneratorTest { - @Test - fun `generates for key`() { - val schema = - ModificationsSchemaGenerator().getModificationSchema( - Key::class, - definition = ActivityType.CREATE_KEY.typeDefinitions!![Key::class]!!, - ) - } -} diff --git a/backend/data/build.gradle b/backend/data/build.gradle index 9501351297..044a722555 100644 --- a/backend/data/build.gradle +++ b/backend/data/build.gradle @@ -90,6 +90,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-jdbc' implementation "org.springframework.boot:spring-boot-starter-validation" + implementation "org.springframework.boot:spring-boot-starter-hateoas" implementation("org.springframework.data:spring-data-envers") implementation("org.springframework.boot:spring-boot-starter-security") implementation 'org.springframework.boot:spring-boot-starter-mail' diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/data/ActivityType.kt b/backend/data/src/main/kotlin/io/tolgee/activity/data/ActivityType.kt index 662c95add3..a11c60cc7d 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/data/ActivityType.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/data/ActivityType.kt @@ -16,7 +16,7 @@ enum class ActivityType( val hideInList: Boolean = false, /** * If true, the activity will be saved even if it does - * not contain any changes in fields market for activity logging + * not contain any changes in fields marked for activity logging */ val saveWithoutModification: Boolean = false, val typeDefinitions: Map, EntityModificationTypeDefinition<*>>? = null, diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupService.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupService.kt index 62bc709010..16b2ed4523 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupService.kt @@ -3,10 +3,10 @@ package io.tolgee.activity.groups import io.tolgee.activity.ModifiedEntitiesType import io.tolgee.component.CurrentDateProvider import io.tolgee.dtos.queryResults.ActivityGroupView +import io.tolgee.dtos.request.ActivityGroupFilters import io.tolgee.model.activity.ActivityGroup import io.tolgee.model.activity.ActivityRevision import io.tolgee.repository.activity.ActivityGroupRepository -import org.jooq.DSLContext import org.springframework.context.ApplicationContext import org.springframework.data.domain.PageImpl import org.springframework.data.domain.Pageable @@ -19,7 +19,6 @@ class ActivityGroupService( private val applicationContext: ApplicationContext, private val activityGroupRepository: ActivityGroupRepository, private val currentDateProvider: CurrentDateProvider, - private val jooqContext: DSLContext, ) { fun addToGroup( activityRevision: ActivityRevision, @@ -108,8 +107,9 @@ class ActivityGroupService( fun getProjectActivityGroups( projectId: Long, pageable: Pageable, + activityGroupFilters: ActivityGroupFilters, ): PageImpl { - return ActivityGroupsProvider(projectId, pageable, applicationContext).get() + return ActivityGroupsProvider(projectId, pageable, activityGroupFilters, applicationContext).get() } private val ActivityGroupDto.isTooOld: Boolean diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupType.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupType.kt index 99d35f6e8b..8ad8dd866f 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupType.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupType.kt @@ -5,7 +5,10 @@ import io.tolgee.activity.data.RevisionType import io.tolgee.activity.groups.matchers.ActivityGroupValueMatcher.Companion.eq import io.tolgee.activity.groups.matchers.ActivityGroupValueMatcher.Companion.modification import io.tolgee.activity.groups.matchers.ActivityGroupValueMatcher.Companion.notNull +import io.tolgee.activity.groups.matchers.modifiedEntity.DefaultMatcher +import io.tolgee.activity.groups.matchers.modifiedEntity.ModifiedEntityMatcher import io.tolgee.activity.groups.viewProviders.createProject.CreateProjectGroupModelProvider +import io.tolgee.activity.groups.viewProviders.keyCreate.CreateKeyGroupModelProvider import io.tolgee.model.Language import io.tolgee.model.Project import io.tolgee.model.Screenshot @@ -20,300 +23,250 @@ import io.tolgee.model.key.screenshotReference.KeyScreenshotReference import io.tolgee.model.translation.Translation import io.tolgee.model.translation.TranslationComment import io.tolgee.model.webhook.WebhookConfig -import org.springframework.context.ApplicationContext +import kotlin.reflect.KClass enum class ActivityGroupType( val sourceActivityTypes: List, - val modifications: List>, - val modelProviderFactory: ((ApplicationContext) -> GroupModelProvider<*>?)? = null, + val modelProviderFactoryClass: KClass>? = null, + val matcher: ModifiedEntityMatcher? = null, ) { SET_TRANSLATION_STATE( listOf(ActivityType.SET_TRANSLATION_STATE, ActivityType.COMPLEX_EDIT), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = Translation::class, - revisionTypes = listOf(RevisionType.MOD), + revisionTypes = listOf(RevisionType.MOD, RevisionType.ADD), modificationProps = listOf(Translation::state, Translation::outdated, Translation::mtProvider), deniedValues = mapOf( Translation::state to TranslationState.REVIEWED, Translation::text to modification(eq(null) to notNull()), ), - countInView = true, ), - ), ), - REVIEW( listOf(ActivityType.SET_TRANSLATION_STATE, ActivityType.COMPLEX_EDIT), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = Translation::class, - revisionTypes = listOf(RevisionType.MOD), + revisionTypes = listOf(RevisionType.MOD, RevisionType.ADD), modificationProps = listOf(Translation::state, Translation::outdated, Translation::mtProvider), allowedValues = mapOf(Translation::state to TranslationState.REVIEWED), - countInView = true, ), - ), ), SET_TRANSLATIONS( listOf(ActivityType.SET_TRANSLATIONS, ActivityType.COMPLEX_EDIT), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = Translation::class, revisionTypes = listOf(RevisionType.ADD, RevisionType.DEL, RevisionType.MOD), modificationProps = listOf(Translation::text), - countInView = true, ), - ), ), DISMISS_AUTO_TRANSLATED_STATE( listOf(ActivityType.DISMISS_AUTO_TRANSLATED_STATE), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = Translation::class, revisionTypes = listOf(RevisionType.MOD), modificationProps = listOf(Translation::auto, Translation::mtProvider), allowedValues = mapOf(Translation::mtProvider to null, Translation::auto to false), - countInView = true, ), - ), ), SET_OUTDATED_FLAG( listOf(ActivityType.SET_OUTDATED_FLAG), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = Translation::class, revisionTypes = listOf(RevisionType.MOD), modificationProps = listOf(Translation::outdated), - countInView = true, ), - ), ), - TRANSLATION_COMMENT_ADD( + ADD_TRANSLATION_COMMENT( listOf(ActivityType.TRANSLATION_COMMENT_ADD), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = TranslationComment::class, revisionTypes = listOf(RevisionType.ADD), - countInView = true, + ).or( + DefaultMatcher( + entityClass = Translation::class, + revisionTypes = listOf(RevisionType.ADD), + ), ), - GroupEntityModificationDefinition( - entityClass = Translation::class, - revisionTypes = listOf(RevisionType.ADD), - ), - ), ), - TRANSLATION_COMMENT_DELETE( + DELETE_TRANSLATION_COMMENT( listOf(ActivityType.TRANSLATION_COMMENT_DELETE), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = TranslationComment::class, revisionTypes = listOf(RevisionType.DEL), - countInView = true, ), - ), ), - TRANSLATION_COMMENT_EDIT( + EDIT_TRANSLATION_COMMENT( listOf(ActivityType.TRANSLATION_COMMENT_EDIT), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = TranslationComment::class, revisionTypes = listOf(RevisionType.MOD), modificationProps = listOf(TranslationComment::text), - countInView = true, ), - ), ), - TRANSLATION_COMMENT_SET_STATE( + SET_TRANSLATION_COMMENT_STATE( listOf(ActivityType.TRANSLATION_COMMENT_SET_STATE), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = TranslationComment::class, revisionTypes = listOf(RevisionType.MOD), modificationProps = listOf(TranslationComment::state), - countInView = true, ), - ), ), - SCREENSHOT_DELETE( + DELETE_SCREENSHOT( listOf(ActivityType.SCREENSHOT_DELETE, ActivityType.COMPLEX_EDIT), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = Screenshot::class, revisionTypes = listOf(RevisionType.DEL), - countInView = true, + ).or( + DefaultMatcher( + entityClass = KeyScreenshotReference::class, + revisionTypes = listOf(RevisionType.DEL), + ), ), - GroupEntityModificationDefinition( - entityClass = KeyScreenshotReference::class, - revisionTypes = listOf(RevisionType.DEL), - ), - ), ), - SCREENSHOT_ADD( + ADD_SCREENSHOT( listOf(ActivityType.SCREENSHOT_ADD, ActivityType.COMPLEX_EDIT), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = Screenshot::class, revisionTypes = listOf(RevisionType.ADD), - countInView = true, + ).or( + DefaultMatcher( + entityClass = KeyScreenshotReference::class, + revisionTypes = listOf(RevisionType.ADD), + ), ), - GroupEntityModificationDefinition( - entityClass = KeyScreenshotReference::class, - revisionTypes = listOf(RevisionType.ADD), - ), - ), ), - KEY_TAGS_EDIT( + EDIT_KEY_TAGS( listOf( ActivityType.KEY_TAGS_EDIT, ActivityType.COMPLEX_EDIT, ActivityType.BATCH_TAG_KEYS, ActivityType.BATCH_UNTAG_KEYS, ), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = KeyMeta::class, - revisionTypes = listOf(RevisionType.MOD), + revisionTypes = listOf(RevisionType.MOD, RevisionType.ADD), modificationProps = listOf(KeyMeta::tags), - countInView = true, + ).or( + DefaultMatcher( + entityClass = Tag::class, + revisionTypes = listOf(RevisionType.ADD, RevisionType.DEL), + ), ), - GroupEntityModificationDefinition( - entityClass = Tag::class, - revisionTypes = listOf(RevisionType.ADD, RevisionType.DEL), - countInView = true, - ), - ), ), - KEY_NAME_EDIT( + EDIT_KEY_NAME( listOf(ActivityType.KEY_NAME_EDIT, ActivityType.COMPLEX_EDIT), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = Key::class, revisionTypes = listOf(RevisionType.MOD), modificationProps = listOf(Key::name, Key::namespace), - countInView = true, - ), - GroupEntityModificationDefinition( - entityClass = Namespace::class, - revisionTypes = listOf(RevisionType.ADD, RevisionType.DEL), - countInView = true, + ).or( + DefaultMatcher( + entityClass = Namespace::class, + revisionTypes = listOf(RevisionType.ADD, RevisionType.DEL), + ), ), - ), ), - KEY_DELETE( + DELETE_KEY( listOf(ActivityType.KEY_DELETE), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = Key::class, revisionTypes = listOf(RevisionType.DEL), - countInView = true, ), - ), ), - KEY_CREATE( + CREATE_KEY( listOf(ActivityType.CREATE_KEY), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = Key::class, revisionTypes = listOf(RevisionType.ADD), - countInView = true, - ), - GroupEntityModificationDefinition( - entityClass = KeyMeta::class, - revisionTypes = listOf(RevisionType.ADD), + ).or( + DefaultMatcher( + entityClass = KeyMeta::class, + revisionTypes = listOf(RevisionType.ADD), + ), + ).or( + DefaultMatcher( + Translation::class, + listOf(RevisionType.ADD), + ), ), - ), + modelProviderFactoryClass = CreateKeyGroupModelProvider::class, ), IMPORT( listOf(ActivityType.IMPORT), - listOf( - GroupEntityModificationDefinition( - entityClass = Key::class, - revisionTypes = listOf(RevisionType.ADD), - countInView = true, - ), - GroupEntityModificationDefinition( - entityClass = KeyMeta::class, - revisionTypes = listOf(RevisionType.ADD, RevisionType.MOD), - modificationProps = listOf(KeyMeta::custom, KeyMeta::description), - ), - GroupEntityModificationDefinition( - entityClass = Translation::class, - revisionTypes = listOf(RevisionType.ADD), - countInView = true, - ), - GroupEntityModificationDefinition( - entityClass = Namespace::class, - revisionTypes = listOf(RevisionType.ADD, RevisionType.DEL), - ), - ), ), CREATE_LANGUAGE( listOf(ActivityType.CREATE_LANGUAGE), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = Language::class, revisionTypes = listOf(RevisionType.ADD), - countInView = true, ), - ), ), EDIT_LANGUAGE( listOf(ActivityType.EDIT_LANGUAGE), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = Language::class, revisionTypes = listOf(RevisionType.MOD), modificationProps = listOf(Language::name, Language::tag, Language::originalName, Language::flagEmoji), - countInView = true, ), - ), ), DELETE_LANGUAGE( listOf(ActivityType.DELETE_LANGUAGE), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = Language::class, revisionTypes = listOf(RevisionType.DEL), - countInView = true, ), - ), ), CREATE_PROJECT( listOf(ActivityType.CREATE_PROJECT), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = Project::class, revisionTypes = listOf(RevisionType.ADD), - countInView = true, ), - ), - modelProviderFactory = { ac -> CreateProjectGroupModelProvider(ac) }, + modelProviderFactoryClass = CreateProjectGroupModelProvider::class, ), EDIT_PROJECT( listOf(ActivityType.EDIT_PROJECT), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = Project::class, revisionTypes = listOf(RevisionType.MOD), modificationProps = @@ -325,61 +278,52 @@ enum class ActivityGroupType( Project::avatarHash, ), ), - ), ), NAMESPACE_EDIT( listOf(ActivityType.NAMESPACE_EDIT, ActivityType.BATCH_SET_KEYS_NAMESPACE), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = Namespace::class, revisionTypes = listOf(RevisionType.MOD), modificationProps = listOf(Namespace::name), - countInView = true, ), - ), ), BATCH_PRE_TRANSLATE_BY_TM( listOf(ActivityType.BATCH_PRE_TRANSLATE_BY_TM), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = Translation::class, revisionTypes = listOf(RevisionType.MOD, RevisionType.ADD), modificationProps = listOf(Translation::state, Translation::text, Translation::outdated, Translation::auto), - countInView = true, ), - ), ), BATCH_MACHINE_TRANSLATE( listOf(ActivityType.BATCH_MACHINE_TRANSLATE), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = Translation::class, revisionTypes = listOf(RevisionType.MOD, RevisionType.ADD), modificationProps = listOf(Translation::state, Translation::text, Translation::outdated, Translation::auto), - countInView = true, ), - ), ), AUTO_TRANSLATE( listOf(ActivityType.AUTO_TRANSLATE), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = Translation::class, revisionTypes = listOf(RevisionType.MOD, RevisionType.ADD), modificationProps = listOf(Translation::state, Translation::text, Translation::outdated, Translation::auto), - countInView = true, ), - ), ), BATCH_CLEAR_TRANSLATIONS( listOf(ActivityType.BATCH_CLEAR_TRANSLATIONS), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = Translation::class, revisionTypes = listOf(RevisionType.MOD), modificationProps = listOf(Translation::state, Translation::text, Translation::outdated, Translation::auto), @@ -390,122 +334,129 @@ enum class ActivityGroupType( Translation::outdated to false, Translation::auto to false, ), - countInView = true, ), - ), ), BATCH_COPY_TRANSLATIONS( listOf(ActivityType.BATCH_COPY_TRANSLATIONS), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = Translation::class, revisionTypes = listOf(RevisionType.MOD, RevisionType.ADD), modificationProps = listOf(Translation::state, Translation::text, Translation::outdated, Translation::auto), - countInView = true, ), - ), ), BATCH_SET_TRANSLATION_STATE( listOf(ActivityType.BATCH_SET_TRANSLATION_STATE), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = Translation::class, revisionTypes = listOf(RevisionType.MOD), modificationProps = listOf(Translation::state, Translation::outdated, Translation::auto), - countInView = true, ), - ), ), CONTENT_DELIVERY_CONFIG_CREATE( listOf(ActivityType.CONTENT_DELIVERY_CONFIG_CREATE), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = ContentDeliveryConfig::class, revisionTypes = listOf(RevisionType.ADD), ), - ), ), CONTENT_DELIVERY_CONFIG_UPDATE( listOf(ActivityType.CONTENT_DELIVERY_CONFIG_UPDATE), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = ContentDeliveryConfig::class, revisionTypes = listOf(RevisionType.MOD), ), - ), ), CONTENT_DELIVERY_CONFIG_DELETE( listOf(ActivityType.CONTENT_DELIVERY_CONFIG_UPDATE), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = ContentDeliveryConfig::class, revisionTypes = listOf(RevisionType.DEL), ), - ), ), CONTENT_STORAGE_CREATE( listOf(ActivityType.CONTENT_STORAGE_CREATE), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = ContentStorage::class, revisionTypes = listOf(RevisionType.ADD), ), - ), ), CONTENT_STORAGE_UPDATE( listOf(ActivityType.CONTENT_STORAGE_UPDATE), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = ContentStorage::class, revisionTypes = listOf(RevisionType.MOD), ), - ), ), CONTENT_STORAGE_DELETE( listOf(ActivityType.CONTENT_STORAGE_DELETE), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = ContentStorage::class, revisionTypes = listOf(RevisionType.DEL), ), - ), ), WEBHOOK_CONFIG_CREATE( listOf(ActivityType.WEBHOOK_CONFIG_CREATE), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = WebhookConfig::class, revisionTypes = listOf(RevisionType.ADD), ), - ), ), WEBHOOK_CONFIG_UPDATE( listOf(ActivityType.WEBHOOK_CONFIG_CREATE), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = WebhookConfig::class, revisionTypes = listOf(RevisionType.MOD), ), - ), ), WEBHOOK_CONFIG_DELETE( listOf(ActivityType.WEBHOOK_CONFIG_CREATE), - listOf( - GroupEntityModificationDefinition( + matcher = + DefaultMatcher( entityClass = WebhookConfig::class, revisionTypes = listOf(RevisionType.DEL), ), - ), ), + + ; + + fun getProvidingModelTypes(): Pair?, KClass<*>?>? { + val arguments = + modelProviderFactoryClass + ?.supertypes + ?.firstOrNull() + ?.arguments ?: return null + + val groupType = + arguments.firstOrNull() + ?.type + ?.classifier as? KClass<*> + + val itemType = + arguments[1] + .type + ?.classifier as? KClass<*> + + return groupType to itemType + } } diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGrouper.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGrouper.kt index bffffc59c5..6620dafc6f 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGrouper.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGrouper.kt @@ -1,16 +1,10 @@ package io.tolgee.activity.groups import io.tolgee.activity.ModifiedEntitiesType -import io.tolgee.activity.data.PropertyModification -import io.tolgee.activity.groups.matchers.ActivityGroupValueMatcher -import io.tolgee.model.EntityWithId -import io.tolgee.model.activity.ActivityModifiedEntity +import io.tolgee.activity.groups.matchers.modifiedEntity.StoringContext import io.tolgee.model.activity.ActivityRevision import jakarta.persistence.EntityManager import org.springframework.context.ApplicationContext -import java.util.IdentityHashMap -import kotlin.reflect.KClass -import kotlin.reflect.KProperty1 class ActivityGrouper( private val activityRevision: ActivityRevision, @@ -55,60 +49,13 @@ class ActivityGrouper( return false } - return modifiedEntities.any { modifiedEntity -> - this.modifications.any { definition -> - definition.matchesModifiedEntity(modifiedEntity) + return modifiedEntities.any { modifiedEntityEntry -> + modifiedEntityEntry.value.values.any { modifiedEntity -> + this.matcher?.match(StoringContext(modifiedEntity)) ?: true } } } - private fun GroupEntityModificationDefinition<*>.matchesModifiedEntity(entityEntry: ModifiedEntityType): Boolean { - if (entityEntry.key != entityClass) { - return false - } - - val isAnyWithAllowedType = entityEntry.value.any { it.value.revisionType in revisionTypes } - if (!isAnyWithAllowedType) { - return false - } - - val anyWithModifiedColumn = - entityEntry.value.values.any { entity -> - entity.modifications.any { modification -> - modificationProps?.any { it.name == modification.key } ?: true - } - } - - if (!anyWithModifiedColumn) { - return false - } - - if (!allowedValues.matchesEntityModification(entityEntry)) { - return false - } - - val isDenied = deniedValues?.matchesEntityModification(entityEntry) ?: false - return !isDenied - } - - private fun Map, Any?>?.matchesEntityModification(entry: ModifiedEntityType): Boolean { - return entry.value.values.any { entity -> - entity.modifications.any { modification -> - this?.all { compareValue(it.value, modification.value) && it.key.name == modification.key } ?: true - } - } - } - - private fun compareValue( - value: Any?, - value1: PropertyModification, - ): Boolean { - return when (value) { - is ActivityGroupValueMatcher -> value.match(value1.new) - else -> value == value1.new - } - } - private val type = activityRevision.type private val activityGroupService by lazy { @@ -119,5 +66,3 @@ class ActivityGrouper( applicationContext.getBean(EntityManager::class.java) } } - -private typealias ModifiedEntityType = Map.Entry, IdentityHashMap> diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupsProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupsProvider.kt index 7a87290290..de0834fe89 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupsProvider.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupsProvider.kt @@ -1,15 +1,15 @@ package io.tolgee.activity.groups -import io.tolgee.activity.groups.matchers.ActivityGroupValueMatcher -import io.tolgee.activity.groups.matchers.EqualsValueMatcher +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue import io.tolgee.api.SimpleUserAccount import io.tolgee.dtos.queryResults.ActivityGroupView -import org.jooq.Condition +import io.tolgee.dtos.request.ActivityGroupFilters import org.jooq.DSLContext -import org.jooq.Field import org.jooq.JSON import org.jooq.impl.DSL import org.jooq.impl.DSL.field +import org.jooq.impl.DSL.jsonArrayAgg import org.jooq.impl.DSL.max import org.jooq.impl.DSL.table import org.springframework.context.ApplicationContext @@ -17,10 +17,14 @@ import org.springframework.data.domain.PageImpl import org.springframework.data.domain.Pageable import java.util.* -class ActivityGroupsProvider(val projectId: Long, val pageable: Pageable, applicationContext: ApplicationContext) { +class ActivityGroupsProvider( + val projectId: Long, + val pageable: Pageable, + val filters: ActivityGroupFilters, + applicationContext: ApplicationContext, +) { fun get(): PageImpl { page.forEach { - it.counts = counts[it.id] ?: emptyMap() it.data = dataViews[it.id] } @@ -29,7 +33,25 @@ class ActivityGroupsProvider(val projectId: Long, val pageable: Pageable, applic private val page by lazy { val from = table("activity_group").`as`("ag") - val where = field("ag.project_id").eq(projectId) + var where = field("ag.project_id").eq(projectId) + + var having = DSL.noCondition() + + val lmeJsonArrayAggField = jsonArrayAgg(field("lme.entity_id")).`as`("lme_entity_ids") + val ldeJsonArrayAggField = jsonArrayAgg(field("lde.entity_id")).`as`("lde_entity_ids") + + if (filters.filterType != null) { + where = where.and(field("ag.type").eq(filters.filterType!!.name)) + } + + if (filters.filterLanguageIdIn != null) { + val languageIdsJson = JSON.json(objectMapper.writeValueAsString(filters.filterLanguageIdIn)) + having = lmeJsonArrayAggField.contains(languageIdsJson).and(ldeJsonArrayAggField.contains(languageIdsJson)) + } + + if (filters.filterAuthorUserIdIn != null) { + where = where.and(field("ag.author_id").`in`(filters.filterAuthorUserIdIn)) + } val count = jooqContext.selectCount().from(from).where(where).fetchOne(0, Long::class.java)!! @@ -44,6 +66,8 @@ class ActivityGroupsProvider(val projectId: Long, val pageable: Pageable, applic field("ua.name"), field("ua.avatar_hash"), field("ua.deleted_at").isNotNull, + lmeJsonArrayAggField, + ldeJsonArrayAggField, ) .from(from) .leftJoin(table("activity_revision_activity_groups").`as`("arag")) @@ -51,8 +75,16 @@ class ActivityGroupsProvider(val projectId: Long, val pageable: Pageable, applic .leftJoin(table("activity_revision").`as`("ar")) .on(field("ar.id").eq(field("arag.activity_revisions_id"))) .leftJoin(table("user_account").`as`("ua")).on(field("ag.author_id").eq(field("ua.id"))) + .leftJoin(table("activity_modified_entity").`as`("lme")).on( + field("ar.id").eq(field("lme.activity_revision_id")) + .and(field("lme.entity_class").eq("Language")), + ).leftJoin(table("activity_describing_entity").`as`("lde")).on( + field("ar.id").eq(field("lde.activity_revision_id")) + .and(field("lde.entity_class").eq("Language")), + ) .where(where) .groupBy(field("ag.id"), field("ua.id")) + .having(having) .orderBy(max(field("ar.timestamp")).desc()) .limit(pageable.pageSize) .offset(pageable.offset).fetch().map { @@ -60,107 +92,43 @@ class ActivityGroupsProvider(val projectId: Long, val pageable: Pageable, applic it[0] as Long, ActivityGroupType.valueOf(it[1] as String), it[3] as Date, - author = object : SimpleUserAccount { - override val id: Long = it[4] as Long - override val username: String = it[5] as String - override val name: String = it[6] as String - override val avatarHash: String? = it[7] as String? - override val deleted: Boolean = it[8] as Boolean - } + author = + object : SimpleUserAccount { + override val id: Long = it[4] as Long + override val username: String = it[5] as String + override val name: String = it[6] as String + override val avatarHash: String? = it[7] as String? + override val deleted: Boolean = it[8] as Boolean + }, + mentionedLanguageIds = parseMentionedLanguageIds(it), ) } PageImpl(result, pageable, count) } - private val counts by lazy { - byType.flatMap { (type, items) -> - getCounts(type, items).map { it.key to it.value } - }.toMap() + private fun parseMentionedLanguageIds(it: org.jooq.Record): List { + val lmeIds = it.getJsonValue>("lme_entity_ids") ?: emptyList() + val ldeIds = it.getJsonValue>("lde_entity_ids") ?: emptyList() + return (lmeIds + ldeIds).filterNotNull().toSet().toList() + } + + private inline fun org.jooq.Record.getJsonValue(fieldName: String): T? { + val string = this.getValue(fieldName, String::class.java) ?: return null + return objectMapper.readValue(string) } private val dataViews by lazy { byType.flatMap { (type, items) -> - val provider = type.modelProviderFactory?.invoke(applicationContext) - provider?.provide(items.map { it.id })?.map { it.key to it.value } ?: emptyList() + val provider = + type.modelProviderFactoryClass?.let { applicationContext.getBean(it.java) } + provider?.provideGroupModel(items.map { it.id })?.map { it.key to it.value } ?: emptyList() }.toMap() } private val byType by lazy { page.groupBy { it.type } } - private fun getModificationCondition(definition: GroupEntityModificationDefinition<*>): Condition { - return field("ame.entity_class").eq(definition.entityClass.simpleName) - .and(field("ame.revision_type").`in`(definition.revisionTypes.map { it.ordinal })) - .also { - if (definition.modificationProps != null) { - it.and("array(select jsonb_object_keys(ame.modifications)) && ${allowedModString(definition)}") - } - }.also { - it.and(getAllowedValuesCondition(definition)) - } - .also { - it.and(getDeniedValuesCondition(definition)) - } - } - - private fun getAllowedValuesCondition(definition: GroupEntityModificationDefinition<*>): Condition { - val allowedValues = definition.allowedValues ?: return DSL.noCondition() - val conditions = getValueMatcherConditions(allowedValues) - return DSL.and(conditions) - } - - private fun getDeniedValuesCondition(definition: GroupEntityModificationDefinition<*>): Condition { - val allowedValues = definition.allowedValues ?: return DSL.noCondition() - val conditions = getValueMatcherConditions(allowedValues) - return DSL.not(DSL.or(conditions)) - } - - private fun getValueMatcherConditions(values: Map): List { - return values.map { - val matcher = - when (val requiredValue = it.value) { - is ActivityGroupValueMatcher -> requiredValue - else -> EqualsValueMatcher(requiredValue) - } - - @Suppress("UNCHECKED_CAST") - matcher.createRootSqlCondition(field("ame.modifications") as Field) - } - } - - private fun allowedModString(definition: GroupEntityModificationDefinition<*>): String { - return "{${definition.modificationProps?.joinToString(",")}}" - } - - private fun getCounts( - type: ActivityGroupType, - items: List, - ): MutableMap> { - val groupIds = items.map { it.id } - val result = mutableMapOf>() - type.modifications - .filter { it.countInView } - .forEach { definition -> - val queryResult = - jooqContext - .select(field("arag.activity_groups_id"), DSL.count()) - .from(table("activity_modified_entity").`as`("ame")) - .join(table("activity_revision").`as`("ar")) - .on(field("ar.id").eq(field("ame.activity_revision_id"))) - .join(table("activity_revision_activity_groups").`as`("arag")) - .on(field("ar.id").eq(field("arag.activity_revisions_id"))) - .where(field("arag.activity_groups_id").`in`(groupIds).and(getModificationCondition(definition))) - .groupBy(field("arag.activity_groups_id")).fetch() - queryResult.forEach { - val groupMap = - result.computeIfAbsent(it[0] as Long) { - mutableMapOf() - } - groupMap[definition.entityClass.simpleName!!] = (it[1] as Int).toLong() - } - } - return result - } - private val jooqContext = applicationContext.getBean(DSLContext::class.java) + + private val objectMapper = applicationContext.getBean(ObjectMapper::class.java) } diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/GroupEntityModificationDefinition.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/GroupEntityModificationDefinition.kt deleted file mode 100644 index 89d267f2d9..0000000000 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/GroupEntityModificationDefinition.kt +++ /dev/null @@ -1,14 +0,0 @@ -package io.tolgee.activity.groups - -import io.tolgee.activity.data.RevisionType -import kotlin.reflect.KClass -import kotlin.reflect.KProperty1 - -class GroupEntityModificationDefinition( - val entityClass: KClass, - val revisionTypes: List, - val modificationProps: List>? = null, - val allowedValues: Map, Any?>? = null, - val deniedValues: Map, Any?>? = null, - val countInView: Boolean = false, -) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/GroupModelProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/GroupModelProvider.kt index 0872c8bb82..ea6fef7727 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/GroupModelProvider.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/GroupModelProvider.kt @@ -1,5 +1,13 @@ package io.tolgee.activity.groups -interface GroupModelProvider { - fun provide(groupIds: List): Map +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable + +interface GroupModelProvider { + fun provideGroupModel(groupIds: List): Map + + fun provideItemModel( + groupId: Long, + pageable: Pageable, + ): Page } diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/LanguageModel.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/baseModels/ActivityGroupLanguageModel.kt similarity index 60% rename from backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/LanguageModel.kt rename to backend/data/src/main/kotlin/io/tolgee/activity/groups/baseModels/ActivityGroupLanguageModel.kt index 624bd1342f..a40c075219 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/LanguageModel.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/baseModels/ActivityGroupLanguageModel.kt @@ -1,11 +1,11 @@ -package io.tolgee.activity.groups.viewProviders.createProject +package io.tolgee.activity.groups.baseModels import io.tolgee.api.ILanguageModel -class LanguageModel( +class ActivityGroupLanguageModel( override val id: Long, override val name: String, override val originalName: String, override val tag: String, - override val flagEmoji: String + override val flagEmoji: String, ) : ILanguageModel diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/ModifiedEntityView.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/ModifiedEntityView.kt new file mode 100644 index 0000000000..59b430f31f --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/ModifiedEntityView.kt @@ -0,0 +1,26 @@ +package io.tolgee.activity.groups.data + +import io.tolgee.activity.data.PropertyModification + +class ModifiedEntityView( + val entityId: Long, + val entityClass: String, + val describingData: Map, + val describingRelations: Map, + val modifications: Map, +) { + private inline fun Map.getFieldFromMap(name: String): T? { + this[name].let { + return it as? T + } + } + + inline fun getFieldFromViewNullable(name: String): T? { + return this.describingData[name] as? T ?: this.modifications[name]?.let { it.new as? T } + } + + inline fun getFieldFromView(name: String): T { + return this.describingData[name] as? T ?: this.modifications[name]?.let { it.new as? T } + ?: throw IllegalArgumentException("Field $name not found in modifications or describing data") + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/CountsProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/CountsProvider.kt new file mode 100644 index 0000000000..ab2b8e3e13 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/CountsProvider.kt @@ -0,0 +1,60 @@ +package io.tolgee.activity.groups.dataProviders + +import io.tolgee.activity.groups.ActivityGroupType +import io.tolgee.activity.groups.matchers.modifiedEntity.SqlContext +import org.jooq.DSLContext +import org.jooq.JSON +import org.jooq.impl.DSL + +class CountsProvider( + private val jooqContext: DSLContext, + private val groupType: ActivityGroupType, + private val entityClasses: List, + private val groupIds: List, +) { + private val activityModifiedEntityTable = DSL.table("activity_modified_entity").`as`("ame") + private val entityClassField = DSL.field("ame.entity_class", String::class.java) + private val activityRevisionTable = DSL.table("activity_revision").`as`("ar") + private val activityRevisionActivityGroupsTable = DSL.table("activity_revision_activity_groups").`as`("arag") + private val groupIdField = DSL.field("arag.activity_groups_id", Long::class.java) + private val countField = DSL.count() + + fun provide(): Map> { + val sqlContext = + SqlContext( + modificationsField = DSL.field("ame.modifications", JSON::class.java), + entityClassField = entityClassField, + revisionTypeField = DSL.field("ame.revision_type", Int::class.java), + ) + + val queryResult = + jooqContext + .select( + groupIdField, + entityClassField, + countField, + ) + .from(activityModifiedEntityTable) + .join(activityRevisionTable) + .on( + DSL.field("ame.activity_revision_id", Long::class.java) + .eq(DSL.field("ar.id", Long::class.java)), + ) + .join(activityRevisionActivityGroupsTable) + .on( + DSL.field("ar.id", Long::class.java) + .eq(DSL.field("arag.activity_revisions_id", Long::class.java)), + ) + .where( + groupIdField.`in`(groupIds).and(entityClassField.`in`(entityClasses)).and( + groupType.matcher?.match(sqlContext), + ), + ) + .groupBy(entityClassField, groupIdField) + .fetch() + + return queryResult.groupBy { groupIdField.get(it)!! }.mapValues { rows -> + rows.value.associate { entityClassField.getValue(it)!! to countField.getValue(it)!! } + } + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/GroupDataProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/GroupDataProvider.kt new file mode 100644 index 0000000000..d644580935 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/GroupDataProvider.kt @@ -0,0 +1,55 @@ +package io.tolgee.activity.groups.dataProviders + +import com.fasterxml.jackson.databind.ObjectMapper +import io.tolgee.activity.groups.ActivityGroupType +import io.tolgee.activity.groups.data.ModifiedEntityView +import io.tolgee.model.EntityWithId +import org.jooq.DSLContext +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.stereotype.Component +import kotlin.reflect.KClass + +@Component +class GroupDataProvider( + private val jooqContext: DSLContext, + private val objectMapper: ObjectMapper, +) { + fun provideCounts( + groupType: ActivityGroupType, + entityClass: KClass, + groupIds: List, + ): Map { + val simpleNameString = entityClass.java.simpleName + + val result = + CountsProvider( + groupType = groupType, + entityClasses = listOf(simpleNameString), + groupIds = groupIds, + jooqContext = jooqContext, + ).provide() + + return result.map { (groupId, counts) -> + groupId to (counts[simpleNameString] ?: 0) + }.toMap() + } + + fun provideRelevantModifiedEntities( + groupType: ActivityGroupType, + entityClass: KClass, + groupId: Long, + pageable: Pageable, + ): Page { + val simpleNameString = entityClass.java.simpleName + + return RelevantModifiedEntitiesProvider( + jooqContext = jooqContext, + objectMapper = objectMapper, + groupType = groupType, + entityClasses = listOf(simpleNameString), + groupId = groupId, + pageable = pageable, + ).provide() + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/RelevantModifiedEntitiesProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/RelevantModifiedEntitiesProvider.kt new file mode 100644 index 0000000000..84b7863b7d --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/RelevantModifiedEntitiesProvider.kt @@ -0,0 +1,91 @@ +package io.tolgee.activity.groups.dataProviders + +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue +import io.tolgee.activity.groups.ActivityGroupType +import io.tolgee.activity.groups.data.ModifiedEntityView +import io.tolgee.activity.groups.matchers.modifiedEntity.SqlContext +import org.jooq.DSLContext +import org.jooq.JSON +import org.jooq.SelectField +import org.jooq.impl.DSL +import org.springframework.data.domain.Page +import org.springframework.data.domain.PageImpl +import org.springframework.data.domain.Pageable + +class RelevantModifiedEntitiesProvider( + private val jooqContext: DSLContext, + private val objectMapper: ObjectMapper, + private val groupType: ActivityGroupType, + private val entityClasses: List, + private val groupId: Long, + private val pageable: Pageable, +) { + private val activityModifiedEntityTable = DSL.table("activity_modified_entity").`as`("ame") + private val entityClassField = DSL.field("ame.entity_class", String::class.java) + private val activityRevisionTable = DSL.table("activity_revision").`as`("ar") + private val activityRevisionActivityGroupsTable = DSL.table("activity_revision_activity_groups").`as`("arag") + private val groupIdField = DSL.field("arag.activity_groups_id", Long::class.java) + private val entityIdField = DSL.field("ame.entity_id", Long::class.java) + private val describingDataField = DSL.field("ame.describing_data", JSON::class.java) + private val describingRelationsField = DSL.field("ame.describing_relations", JSON::class.java) + private val modificationsField = DSL.field("ame.modifications", JSON::class.java) + private val sqlContext = + SqlContext( + modificationsField = DSL.field("ame.modifications", JSON::class.java), + entityClassField = entityClassField, + revisionTypeField = DSL.field("ame.revision_type", Int::class.java), + ) + + fun provide(): Page { + val queryResult = + getDataQuery() + .fetch() + + val content = + queryResult.map { + ModifiedEntityView( + entityId = it.get(entityIdField)!!, + entityClass = it.get(entityClassField)!!, + describingData = objectMapper.readValue(it.get(describingDataField).data()), + describingRelations = objectMapper.readValue(it.get(describingRelationsField).data()), + modifications = objectMapper.readValue(it.get(modificationsField).data()), + ) + } + + val count = getCountQuery().fetchOne(0, Int::class.java) ?: 0 + + return PageImpl(content, pageable, count.toLong()) + } + + private fun getDataQuery() = + getQueryBase( + entityIdField, + entityClassField, + describingDataField, + describingRelationsField, + modificationsField, + ) + + private fun getCountQuery() = getQueryBase(DSL.count()) + + private fun getQueryBase(vararg fields: SelectField<*>) = + jooqContext + .select(*fields) + .from(activityModifiedEntityTable) + .join(activityRevisionTable) + .on( + DSL.field("ame.activity_revision_id", Long::class.java) + .eq(DSL.field("ar.id", Long::class.java)), + ) + .join(activityRevisionActivityGroupsTable) + .on( + DSL.field("ar.id", Long::class.java) + .eq(DSL.field("arag.activity_revisions_id", Long::class.java)), + ) + .where( + groupIdField.`in`(groupId).and(entityClassField.`in`(entityClasses)).and( + groupType.matcher?.match(sqlContext), + ), + ) +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/DefaultMatcher.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/DefaultMatcher.kt new file mode 100644 index 0000000000..e0e6a5e4c4 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/DefaultMatcher.kt @@ -0,0 +1,126 @@ +package io.tolgee.activity.groups.matchers.modifiedEntity + +import io.tolgee.activity.data.PropertyModification +import io.tolgee.activity.data.RevisionType +import io.tolgee.activity.groups.matchers.ActivityGroupValueMatcher +import io.tolgee.activity.groups.matchers.EqualsValueMatcher +import org.jooq.Condition +import org.jooq.impl.DSL +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 + +class DefaultMatcher( + val entityClass: KClass, + val revisionTypes: List, + val modificationProps: List>? = null, + val allowedValues: Map, Any?>? = null, + val deniedValues: Map, Any?>? = null, +) : ModifiedEntityMatcher { + override fun match(context: StoringContext): Boolean { + if (context.modifiedEntity.entityClass != entityClass.simpleName) { + return false + } + + if (context.modifiedEntity.revisionType !in revisionTypes) { + return false + } + + val hasModifiedColumn = + context.modifiedEntity.modifications.any { modification -> + modificationProps?.any { it.name == modification.key } ?: true + } + + if (!hasModifiedColumn) { + return false + } + + if (!isAllValuesAllowed(context)) { + return false + } + + return isNoValueDenied(context) + } + + private fun isAllValuesAllowed(context: StoringContext): Boolean { + return context.modifiedEntity.modifications.all { modification -> + val allowedValueDefinition = + allowedValues?.filterKeys { it.name == modification.key }?.values?.firstOrNull() ?: return@all true + compareValue(allowedValueDefinition, modification.value) + } + } + + private fun isNoValueDenied(context: StoringContext): Boolean { + val isAnyDenied = + context.modifiedEntity.modifications.any { modification -> + deniedValues?.any { it.key.name == modification.key && compareValue(it.value, modification.value) } ?: false + } + return !isAnyDenied + } + + private fun compareValue( + matcher: Any?, + modification: PropertyModification, + ): Boolean { + return when (matcher) { + is ActivityGroupValueMatcher -> matcher.match(modification) + else -> matcher == modification.new + } + } + + override fun match(context: SqlContext): Condition { + return DSL.and( + getEntityClassCondition(context), + getRevisionTypeCondition(context), + getModificationPropsCondition(context), + getAllowedValuesCondition(context), + getDeniedValuesCondition(context), + ) + } + + private fun getModificationPropsCondition(context: SqlContext): Condition { + if (modificationProps != null) { + return DSL.condition( + "array(select jsonb_object_keys(${context.modificationsField.name})) && ${allowedModString()}", + ) + } + return DSL.noCondition() + } + + private fun getRevisionTypeCondition(context: SqlContext): Condition { + return context.revisionTypeField.`in`(revisionTypes.map { it.ordinal }) + } + + private fun getEntityClassCondition(context: SqlContext): Condition { + return context.entityClassField.eq(entityClass.simpleName) + } + + private fun allowedModString(): String { + return "{${modificationProps?.joinToString(",")}}" + } + + private fun getAllowedValuesCondition(context: SqlContext): Condition { + val allowedValues = allowedValues ?: return DSL.noCondition() + val conditions = getValueMatcherConditions(context, allowedValues) + return DSL.and(conditions) + } + + private fun getDeniedValuesCondition(context: SqlContext): Condition { + val deniedValues = deniedValues ?: return DSL.noCondition() + val conditions = getValueMatcherConditions(context, deniedValues) + return DSL.not(DSL.or(conditions)) + } + + private fun getValueMatcherConditions( + context: SqlContext, + values: Map, + ): List { + return values.map { + val matcher = + when (val requiredValue = it.value) { + is ActivityGroupValueMatcher -> requiredValue + else -> EqualsValueMatcher(requiredValue) + } + matcher.createRootSqlCondition(context.modificationsField) + } + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/ModifiedEntityMatcher.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/ModifiedEntityMatcher.kt new file mode 100644 index 0000000000..ea4bf7266a --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/ModifiedEntityMatcher.kt @@ -0,0 +1,34 @@ +package io.tolgee.activity.groups.matchers.modifiedEntity + +import org.jooq.Condition +import org.jooq.impl.DSL + +interface ModifiedEntityMatcher { + fun match(context: StoringContext): Boolean + + fun match(context: SqlContext): Condition + + fun and(other: ModifiedEntityMatcher): ModifiedEntityMatcher { + return object : ModifiedEntityMatcher { + override fun match(context: StoringContext): Boolean { + return this@ModifiedEntityMatcher.match(context) && other.match(context) + } + + override fun match(context: SqlContext): Condition { + return DSL.and(this@ModifiedEntityMatcher.match(context), other.match(context)) + } + } + } + + fun or(other: ModifiedEntityMatcher): ModifiedEntityMatcher { + return object : ModifiedEntityMatcher { + override fun match(context: StoringContext): Boolean { + return this@ModifiedEntityMatcher.match(context) || other.match(context) + } + + override fun match(context: SqlContext): Condition { + return DSL.or(this@ModifiedEntityMatcher.match(context), other.match(context)) + } + } + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/SqlContext.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/SqlContext.kt new file mode 100644 index 0000000000..16f6647a61 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/SqlContext.kt @@ -0,0 +1,13 @@ +package io.tolgee.activity.groups.matchers.modifiedEntity + +import org.jooq.Field +import org.jooq.JSON + +/** + * This is all the context that can be used when data are queried from the database + */ +class SqlContext( + val modificationsField: Field, + var entityClassField: Field, + var revisionTypeField: Field, +) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/StoringContext.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/StoringContext.kt new file mode 100644 index 0000000000..598f53973a --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/StoringContext.kt @@ -0,0 +1,10 @@ +package io.tolgee.activity.groups.matchers.modifiedEntity + +import io.tolgee.model.activity.ActivityModifiedEntity + +/** + * This is all the context that is provided when storing the activity data + */ +class StoringContext( + val modifiedEntity: ActivityModifiedEntity, +) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/CreateProjectGroupModel.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/CreateProjectGroupModel.kt index 9f8a1a69a2..62cf7391b5 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/CreateProjectGroupModel.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/CreateProjectGroupModel.kt @@ -1,8 +1,10 @@ package io.tolgee.activity.groups.viewProviders.createProject +import io.tolgee.activity.groups.baseModels.ActivityGroupLanguageModel + class CreateProjectGroupModel( val id: Long, val name: String, - val languages: List, + val languages: List, val description: String?, ) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/CreateProjectGroupModelProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/CreateProjectGroupModelProvider.kt index 74ced4750d..8c67441b66 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/CreateProjectGroupModelProvider.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/CreateProjectGroupModelProvider.kt @@ -1,58 +1,72 @@ package io.tolgee.activity.groups.viewProviders.createProject import io.tolgee.activity.groups.GroupModelProvider +import io.tolgee.activity.groups.baseModels.ActivityGroupLanguageModel import org.jooq.DSLContext import org.jooq.impl.DSL -import org.springframework.context.ApplicationContext +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.stereotype.Component -class CreateProjectGroupModelProvider(applicationContext: ApplicationContext) : - GroupModelProvider { - override fun provide(groupIds: List): Map { - val query = jooqContext - .select( - DSL.field("arag.activity_groups_id", Long::class.java).`as`("groupId"), - DSL.field("pme.modifications -> 'name' ->> 'new'", String::class.java).`as`("name"), - DSL.field("pme.modifications -> 'description' ->> 'new'", String::class.java).`as`("description"), - DSL.field("pme.entity_id").`as`("id"), - DSL.field("lme.modifications -> 'name' ->> 'new'", String::class.java).`as`("languageName"), - DSL.field("lme.entity_id", Long::class.java).`as`("languageId"), - DSL.field("lme.modifications -> 'tag' ->> 'new'", String::class.java).`as`("languageTag"), - DSL.field("lme.modifications -> 'originalName' ->> 'new'", String::class.java).`as`("languageOriginalName"), - DSL.field("lme.modifications -> 'flagEmoji' ->> 'new'", String::class.java).`as`("languageFlagEmoji") - ) - .from(DSL.table("activity_modified_entity").`as`("pme")) - .join(DSL.table("activity_revision").`as`("ar")) - .on(DSL.field("pme.activity_revision_id").eq(DSL.field("ar.id"))) - .join(DSL.table("activity_revision_activity_groups").`as`("arag")) - .on(DSL.field("ar.id").eq(DSL.field("arag.activity_revisions_id"))) - .join(DSL.table("activity_modified_entity").`as`("lme")) - .on( - DSL.field("lme.entity_class").eq(DSL.inline("Language")) - .and(DSL.field("lme.activity_revision_id").eq(DSL.field("ar.id"))) - ) - .where(DSL.field("arag.activity_groups_id").`in`(groupIds)) - .and(DSL.field("pme.entity_class").eq(DSL.inline("Project"))) - .fetch() +@Component +class CreateProjectGroupModelProvider( + private val jooqContext: DSLContext, +) : + GroupModelProvider { + override fun provideGroupModel(groupIds: List): Map { + val query = + jooqContext + .select( + DSL.field("arag.activity_groups_id", Long::class.java).`as`("groupId"), + DSL.field("pme.modifications -> 'name' ->> 'new'", String::class.java).`as`("name"), + DSL.field("pme.modifications -> 'description' ->> 'new'", String::class.java).`as`("description"), + DSL.field("pme.entity_id").`as`("id"), + DSL.field("lme.modifications -> 'name' ->> 'new'", String::class.java).`as`("languageName"), + DSL.field("lme.entity_id", Long::class.java).`as`("languageId"), + DSL.field("lme.modifications -> 'tag' ->> 'new'", String::class.java).`as`("languageTag"), + DSL.field("lme.modifications -> 'originalName' ->> 'new'", String::class.java).`as`("languageOriginalName"), + DSL.field("lme.modifications -> 'flagEmoji' ->> 'new'", String::class.java).`as`("languageFlagEmoji"), + ) + .from(DSL.table("activity_modified_entity").`as`("pme")) + .join(DSL.table("activity_revision").`as`("ar")) + .on(DSL.field("pme.activity_revision_id").eq(DSL.field("ar.id"))) + .join(DSL.table("activity_revision_activity_groups").`as`("arag")) + .on(DSL.field("ar.id").eq(DSL.field("arag.activity_revisions_id"))) + .join(DSL.table("activity_modified_entity").`as`("lme")) + .on( + DSL.field("lme.entity_class").eq(DSL.inline("Language")) + .and(DSL.field("lme.activity_revision_id").eq(DSL.field("ar.id"))), + ) + .where(DSL.field("arag.activity_groups_id").`in`(groupIds)) + .and(DSL.field("pme.entity_class").eq(DSL.inline("Project"))) + .fetch() return query.groupBy { it["groupId"] as Long }.map { (id, rows) -> - val languages = rows.map { - LanguageModel( - it["languageId"] as Long, - it["languageName"] as String, - it["languageOriginalName"] as String, - it["languageTag"] as String, - it["languageFlagEmoji"] as String - ) - } + val languages = + rows.map { + ActivityGroupLanguageModel( + it["languageId"] as Long, + it["languageName"] as String, + it["languageOriginalName"] as String, + it["languageTag"] as String, + it["languageFlagEmoji"] as String, + ) + } - id to CreateProjectGroupModel( - id = id, - name = rows.first()["name"] as String, - description = rows.first()["description"] as String?, - languages = languages - ) + id to + CreateProjectGroupModel( + id = id, + name = rows.first()["name"] as String, + description = rows.first()["description"] as String?, + languages = languages, + ) }.toMap() } - private val jooqContext = applicationContext.getBean(DSLContext::class.java) + override fun provideItemModel( + groupId: Long, + pageable: Pageable, + ): Page { + return Page.empty() + } } diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupItemModel.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupItemModel.kt new file mode 100644 index 0000000000..a37a00eb45 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupItemModel.kt @@ -0,0 +1,22 @@ +package io.tolgee.activity.groups.viewProviders.keyCreate + +import io.swagger.v3.oas.annotations.media.Schema +import io.tolgee.api.IKeyModel +import io.tolgee.sharedDocs.Key +import org.springframework.hateoas.server.core.Relation + +@Relation(collectionRelation = "items", itemRelation = "item") +class CreateKeyGroupItemModel( + override val id: Long, + override val name: String, + override val namespace: String?, + @Schema(description = Key.IS_PLURAL_FIELD) + val isPlural: Boolean, + @Schema(description = Key.PLURAL_ARG_NAME_FIELD) + val pluralArgName: String?, + @Schema(description = "The base translation value entered when key was created") + val baseTranslationValue: String?, + val tags: Set, + override val description: String?, + override val custom: Map?, +) : IKeyModel diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupModel.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupModel.kt new file mode 100644 index 0000000000..1e7855d5c8 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupModel.kt @@ -0,0 +1,5 @@ +package io.tolgee.activity.groups.viewProviders.keyCreate + +class CreateKeyGroupModel( + val keyCount: Int, +) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupModelProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupModelProvider.kt new file mode 100644 index 0000000000..736491efdc --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupModelProvider.kt @@ -0,0 +1,53 @@ +package io.tolgee.activity.groups.viewProviders.keyCreate + +import io.tolgee.activity.groups.ActivityGroupType +import io.tolgee.activity.groups.GroupModelProvider +import io.tolgee.activity.groups.dataProviders.GroupDataProvider +import io.tolgee.model.key.Key +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.stereotype.Component + +@Component +class CreateKeyGroupModelProvider( + private val groupDataProvider: GroupDataProvider, +) : + GroupModelProvider { + override fun provideGroupModel(groupIds: List): Map { + val keyCounts = + groupDataProvider.provideCounts(ActivityGroupType.CREATE_KEY, groupIds = groupIds, entityClass = Key::class) + + return groupIds.associateWith { + CreateKeyGroupModel( + keyCounts[it] ?: 0, + ) + } + } + + override fun provideItemModel( + groupId: Long, + pageable: Pageable, + ): Page { + val entities = + groupDataProvider.provideRelevantModifiedEntities( + ActivityGroupType.CREATE_KEY, + Key::class, + groupId, + pageable, + ) + + return entities.map { + CreateKeyGroupItemModel( + it.entityId, + name = it.getFieldFromView("name"), + tags = it.getFieldFromViewNullable("tags") ?: emptySet(), + description = it.getFieldFromViewNullable("description"), + custom = it.getFieldFromViewNullable("custom"), + isPlural = false, + pluralArgName = null, + namespace = null, + baseTranslationValue = null, + ) + } + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/ChildItemsProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/ChildItemsProvider.kt index e194c5c519..cd376acef3 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/ChildItemsProvider.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/ChildItemsProvider.kt @@ -4,35 +4,35 @@ import jakarta.persistence.EntityManager import org.springframework.context.ApplicationContext class ChildItemsProvider( - private val activityRevisionId: Long, + private val activityRevisionId: List, private val treeItem: ActivityTreeDefinitionItem, private val applicationContext: ApplicationContext, private val parentIds: List, ) { fun provide(): List { - val rootItems = getRootItemsRaw() + val rootItems = getItemsRaw() return itemsParser.parse(rootItems) } - private fun getRootItemsRaw(): List> { + private fun getItemsRaw(): List> { return entityManager.createNativeQuery( """ select entity_class, ame.describing_data, modifications, ame.entity_id id, 'AME' as type, (ame.describing_relations -> :describingField -> 'entityId')::bigint as parent_id from activity_modified_entity ame where ame.entity_class = :entityClass - and ame.activity_revision_id = :revisionId + and ame.activity_revision_id in :revisionIds and (ame.describing_relations -> :describingField -> 'entityId')::bigint in :ids union select ade.entity_class, ade.data, null, ade.entity_id id, 'ADE' as type, (ade.describing_relations -> :describingField -> 'entityId')::bigint as parent_id from activity_describing_entity ade - where ade.activity_revision_id = :revisionId + where ade.activity_revision_id in :revisionIds and ade.entity_class = :entityClass and (ade.describing_relations -> :describingField -> 'entityId')::bigint in :ids and ade.entity_id not in (select ame.entity_id id from activity_modified_entity ame - where ame.activity_revision_id = :revisionId + where ame.activity_revision_id in :revisionIds and ame.entity_class = :entityClass and (ame.describing_relations -> :describingField -> 'entityId')::bigint in :ids ) @@ -42,7 +42,7 @@ class ChildItemsProvider( ) .setParameter("entityClass", treeItem.entityClass.simpleName) .setParameter("describingField", treeItem.describingField) - .setParameter("revisionId", activityRevisionId) + .setParameter("revisionIds", activityRevisionId) .setParameter("ids", parentIds) .resultList as List> } diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/RootActivityProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/RootActivityProvider.kt index d58bcae9b7..365b08216e 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/RootActivityProvider.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/RootActivityProvider.kt @@ -1,20 +1,27 @@ package io.tolgee.activity.rootActivity +import io.tolgee.activity.groups.matchers.modifiedEntity.DefaultMatcher import jakarta.persistence.EntityManager import org.springframework.context.ApplicationContext import org.springframework.data.domain.Pageable class RootActivityProvider( private val applicationContext: ApplicationContext, - private val activityRevisionId: Long, + private val activityRevisionIds: List, private val activityTreeDefinitionItem: ActivityTreeDefinitionItem, private val pageable: Pageable, + filterModifications: List>? = null, ) { + private val filterModificationsByEntityClass = filterModifications?.groupBy { it.entityClass } + private val rootItems by lazy { + val rootModificationItems = filterModificationsByEntityClass?.get(activityTreeDefinitionItem.entityClass) + RootItemsProvider( pageable, - activityRevisionId, + activityRevisionIds, activityTreeDefinitionItem.entityClass, + rootModificationItems, applicationContext, ).provide() } @@ -31,7 +38,7 @@ class RootActivityProvider( val parentIds = parentItems.map { it.entityId } parentItemDefinition.children.map { (key, item) -> val childItems = - ChildItemsProvider(activityRevisionId, item, applicationContext, parentIds).provide().groupBy { it.parentId } + ChildItemsProvider(activityRevisionIds, item, applicationContext, parentIds).provide().groupBy { it.parentId } childItems.forEach { addChildren(item, it.value) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/RootItemsProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/RootItemsProvider.kt index 0920a735b5..685845d2b2 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/RootItemsProvider.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/RootItemsProvider.kt @@ -1,15 +1,21 @@ package io.tolgee.activity.rootActivity +import io.tolgee.activity.groups.matchers.modifiedEntity.DefaultMatcher import io.tolgee.model.EntityWithId -import jakarta.persistence.EntityManager +import org.jooq.DSLContext +import org.jooq.impl.DSL.field +import org.jooq.impl.DSL.select +import org.jooq.impl.DSL.table +import org.jooq.impl.DSL.value import org.springframework.context.ApplicationContext import org.springframework.data.domain.Pageable import kotlin.reflect.KClass class RootItemsProvider( private val pageable: Pageable, - private val activityRevisionId: Long, + private val activityRevisionIds: List, private val rootEntityClass: KClass, + rootModificationItems: List>?, private val applicationContext: ApplicationContext, ) { fun provide(): List { @@ -17,43 +23,67 @@ class RootItemsProvider( return itemsParser.parse(rootItems) } - private fun getRootItemsRaw(): List> { + fun getRootItemsRaw(): List> { val limit = pageable.pageSize val offset = pageable.offset - return entityManager.createNativeQuery( - """ - select entity_class, ame.describing_data, modifications, ame.entity_id id, 'AME' as type - from activity_modified_entity ame - where ame.entity_class = :entityClass - and ame.activity_revision_id = :revisionId - union - select ade.entity_class, ade.data, null, ade.entity_id id, 'ADE' as type - from activity_describing_entity ade - where ade.activity_revision_id = :revisionId - and ade.entity_class = :entityClass and ade.entity_id not in ( - select ame.entity_id id - from activity_modified_entity ame - where ame.activity_revision_id = :revisionId - and ame.entity_class = :entityClass - ) - order by id - limit :limit - offset :offset - """, - Array::class.java, - ) - .setParameter("entityClass", rootEntityClass.simpleName) - .setParameter("revisionId", activityRevisionId) - .setParameter("limit", limit) - .setParameter("offset", offset) - .resultList as List> - } - val entityManager: EntityManager by lazy { - applicationContext.getBean(EntityManager::class.java) + val activityModifiedEntity = table("activity_modified_entity") + val activityDescribingEntity = table("activity_describing_entity") + + val ameEntityClass = field("entity_class", String::class.java) + val ameDescribingData = field("describing_data", Any::class.java) // Adjust type if needed + val ameModifications = field("modifications", Any::class.java) // Adjust type if needed + val ameEntityId = field("entity_id", Long::class.java) + val ameActivityRevisionId = field("activity_revision_id", Long::class.java) + + val adeEntityClass = field("entity_class", String::class.java) + val adeData = field("data", Any::class.java) // Adjust type if needed + val adeEntityId = field("entity_id", Long::class.java) + val adeActivityRevisionId = field("activity_revision_id", Long::class.java) + + val ameSelect = + select( + ameEntityClass, + ameDescribingData, + ameModifications, + ameEntityId.`as`("id"), + value("AME").`as`("type"), + ).from(activityModifiedEntity) + .where(ameEntityClass.eq(rootEntityClass.simpleName)) + .and(ameActivityRevisionId.`in`(activityRevisionIds)) + + val adeSubQuery = + select(ameEntityId) + .from(activityModifiedEntity) + .where(ameActivityRevisionId.`in`(activityRevisionIds)) + .and(ameEntityClass.eq(rootEntityClass.simpleName)) + + val adeSelect = + select( + adeEntityClass, + adeData, + value(null as Any?).`as`("modifications"), // Adjust type if needed + adeEntityId.`as`("id"), + value("ADE").`as`("type"), + ).from(activityDescribingEntity) + .where(adeActivityRevisionId.`in`(activityRevisionIds)) + .and(adeEntityClass.eq(rootEntityClass.simpleName)) + .and(adeEntityId.notIn(adeSubQuery)) + + val unionQuery = + ameSelect.unionAll(adeSelect) + .orderBy(field("id")) + .limit(limit) + .offset(offset) + + return jooqContext.fetch(unionQuery).map { it.intoArray() }.toList() } - val itemsParser: ActivityItemsParser by lazy { + private val itemsParser: ActivityItemsParser by lazy { applicationContext.getBean(ActivityItemsParser::class.java) } + + private val jooqContext: DSLContext by lazy { + applicationContext.getBean(DSLContext::class.java) + } } diff --git a/backend/data/src/main/kotlin/io/tolgee/api/IKeyModel.kt b/backend/data/src/main/kotlin/io/tolgee/api/IKeyModel.kt new file mode 100644 index 0000000000..5a19fc77b2 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/api/IKeyModel.kt @@ -0,0 +1,23 @@ +package io.tolgee.api + +import io.swagger.v3.oas.annotations.media.Schema + +interface IKeyModel { + @get:Schema(description = "Id of key record") + val id: Long + + @get:Schema(description = "Name of key", example = "this_is_super_key") + val name: String + + @get:Schema(description = "Namespace of key", example = "homepage") + val namespace: String? + + @get:Schema( + description = "Description of key", + example = "This key is used on homepage. It's a label of sign up button.", + ) + val description: String? + + @get:Schema(description = "Custom values of the key") + val custom: Map? +} diff --git a/backend/data/src/main/kotlin/io/tolgee/dtos/queryResults/ActivityGroupView.kt b/backend/data/src/main/kotlin/io/tolgee/dtos/queryResults/ActivityGroupView.kt index d38e657a11..81a5b8b7d3 100644 --- a/backend/data/src/main/kotlin/io/tolgee/dtos/queryResults/ActivityGroupView.kt +++ b/backend/data/src/main/kotlin/io/tolgee/dtos/queryResults/ActivityGroupView.kt @@ -7,10 +7,7 @@ data class ActivityGroupView( val id: Long, val type: ActivityGroupType, val timestamp: java.util.Date, - /** - * Counts of items in this group by entity class name - */ - var counts: Map? = null, var data: Any? = null, - var author: SimpleUserAccount + var author: SimpleUserAccount, + var mentionedLanguageIds: List, ) diff --git a/backend/data/src/main/kotlin/io/tolgee/dtos/request/ActivityGroupFilters.kt b/backend/data/src/main/kotlin/io/tolgee/dtos/request/ActivityGroupFilters.kt new file mode 100644 index 0000000000..66b8cb3c9d --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/dtos/request/ActivityGroupFilters.kt @@ -0,0 +1,9 @@ +package io.tolgee.dtos.request + +import io.tolgee.activity.groups.ActivityGroupType + +class ActivityGroupFilters { + var filterType: ActivityGroupType? = null + var filterLanguageIdIn: List? = null + var filterAuthorUserIdIn: List? = null +} diff --git a/backend/data/src/main/kotlin/io/tolgee/dtos/request/key/CreateKeyDto.kt b/backend/data/src/main/kotlin/io/tolgee/dtos/request/key/CreateKeyDto.kt index 5e6b6793b3..813fd852cd 100644 --- a/backend/data/src/main/kotlin/io/tolgee/dtos/request/key/CreateKeyDto.kt +++ b/backend/data/src/main/kotlin/io/tolgee/dtos/request/key/CreateKeyDto.kt @@ -6,6 +6,7 @@ import io.swagger.v3.oas.annotations.media.Schema import io.tolgee.dtos.RelatedKeyDto import io.tolgee.dtos.WithRelatedKeysInOrder import io.tolgee.model.enums.AssignableTranslationState +import io.tolgee.sharedDocs.Key import io.tolgee.util.getSafeNamespace import jakarta.validation.constraints.NotBlank import jakarta.validation.constraints.Size @@ -40,7 +41,7 @@ class CreateKeyDto( example = "This key is used on homepage. It's a label of sign up button.", ) val description: String? = null, - @Schema(description = "If key is pluralized. If it will be reflected in the editor") + @Schema(description = Key.IS_PLURAL_FIELD) val isPlural: Boolean = false, @Schema( description = diff --git a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityModifiedEntity.kt b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityModifiedEntity.kt index 93d5a096d5..3a580bb006 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityModifiedEntity.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityModifiedEntity.kt @@ -42,7 +42,7 @@ class ActivityModifiedEntity( var modifications: MutableMap = mutableMapOf() /** - * Data, which are discribing the entity, but are not modified by the change + * Data, which are describing the entity, but are not modified by the change */ @Column(columnDefinition = "jsonb") @Type(JsonBinaryType::class) diff --git a/backend/data/src/main/kotlin/io/tolgee/sharedDocs/Key.kt b/backend/data/src/main/kotlin/io/tolgee/sharedDocs/Key.kt new file mode 100644 index 0000000000..1f3855ed26 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/sharedDocs/Key.kt @@ -0,0 +1,6 @@ +package io.tolgee.sharedDocs + +object Key { + const val IS_PLURAL_FIELD = "If key is pluralized. If it will be reflected in the editor" + const val PLURAL_ARG_NAME_FIELD = "The argument name for the plural" +} diff --git a/webapp/src/component/activity/groups/ActivityGroupItem.tsx b/webapp/src/component/activity/groups/ActivityGroupItem.tsx new file mode 100644 index 0000000000..39448a6d54 --- /dev/null +++ b/webapp/src/component/activity/groups/ActivityGroupItem.tsx @@ -0,0 +1,20 @@ +import React, { FC } from 'react'; +import { components } from 'tg.service/apiSchema.generated'; +import { CreateProjectActivityGroup } from './groupTypeComponents/CreateProjectActivityGroup'; +import { CollapsibleActivityGroup } from './groupTypeComponents/CollapsibleActivityGroup'; +import { CreateKeysActivityGroup } from './groupTypeComponents/CreateKeysActivityGroup'; + +export const ActivityGroupItem: FC<{ + item: components['schemas']['ActivityGroupModel']; +}> = (props) => { + switch (props.item.type) { + case 'CREATE_PROJECT': + return ; + case 'CREATE_KEY': + return ; + default: + return ( + {props.item.type} + ); + } +}; diff --git a/webapp/src/component/activity/groups/common/ActivityGroupMentionedLanguages.tsx b/webapp/src/component/activity/groups/common/ActivityGroupMentionedLanguages.tsx new file mode 100644 index 0000000000..fb990b1c19 --- /dev/null +++ b/webapp/src/component/activity/groups/common/ActivityGroupMentionedLanguages.tsx @@ -0,0 +1,27 @@ +import { FC } from 'react'; +import { LanguageIconWithTooltip } from '../../../languages/LanguageIconWithTooltip'; +import { useProjectLanguages } from 'tg.hooks/useProjectLanguages'; +import { Box } from '@mui/material'; + +type ActivityGroupMentionedLanguagesProps = { + mentionedLanguageIds: number[]; +}; + +export const ActivityGroupMentionedLanguages: FC< + ActivityGroupMentionedLanguagesProps +> = (props) => { + const languages = useProjectLanguages(); + + //filter only mentioned + const used = languages.filter((l) => + props.mentionedLanguageIds.includes(l.id) + ); + + return ( + + {used.map((l, i) => ( + + ))} + + ); +}; diff --git a/webapp/src/component/activity/groups/groupTypeComponents/CollapsibleActivityGroup.tsx b/webapp/src/component/activity/groups/groupTypeComponents/CollapsibleActivityGroup.tsx new file mode 100644 index 0000000000..e9e1346743 --- /dev/null +++ b/webapp/src/component/activity/groups/groupTypeComponents/CollapsibleActivityGroup.tsx @@ -0,0 +1,24 @@ +import React, { FC } from 'react'; +import { Box, Button } from '@mui/material'; + +export const CollapsibleActivityGroup: FC<{ + expandedChildren?: React.ReactNode; +}> = (props) => { + const [expanded, setExpanded] = React.useState(false); + + const expandedContent = expanded + ? props.expandedChildren + ? props.expandedChildren + : false + : null; + + return ( + + {props.children} + {props.expandedChildren !== undefined && ( + + )} + {expandedContent && {expandedContent}} + + ); +}; diff --git a/webapp/src/component/activity/groups/groupTypeComponents/CreateKeysActivityGroup.tsx b/webapp/src/component/activity/groups/groupTypeComponents/CreateKeysActivityGroup.tsx new file mode 100644 index 0000000000..d1af8b4bfb --- /dev/null +++ b/webapp/src/component/activity/groups/groupTypeComponents/CreateKeysActivityGroup.tsx @@ -0,0 +1,69 @@ +import React, { FC } from 'react'; +import { components } from 'tg.service/apiSchema.generated'; +import { CollapsibleActivityGroup } from './CollapsibleActivityGroup'; +import { useApiQuery } from 'tg.service/http/useQueryApi'; +import { useProject } from 'tg.hooks/useProject'; +import { PaginatedHateoasList } from '../../../common/list/PaginatedHateoasList'; +import { + Table, + TableBody, + TableCell, + TableHead, + TableRow, +} from '@mui/material'; +import { T } from '@tolgee/react'; + +type Group = components['schemas']['ActivityGroupCreateKeyModel']; + +export const CreateKeysActivityGroup: FC<{ + group: Group; +}> = ({ group }) => { + return ( + } + > + {group.author?.name} Created {group.data?.keyCount} keys{' '} + + ); +}; + +const ExpandedContent: FC<{ group: Group }> = (props) => { + const project = useProject(); + + const [page, setPage] = React.useState(0); + + const loadable = useApiQuery({ + url: '/v2/projects/{projectId}/activity/group-items/create-key/{groupId}', + method: 'get', + path: { projectId: project.id, groupId: props.group.id }, + query: { + page: page, + size: 20, + }, + }); + return ( + ( + + {i.name} + + )} + onPageChange={(p) => setPage(p)} + loadable={loadable} + /> + ); +}; + +const TheTable: FC = (props) => { + return ( + + + + + + + {props.children} +
+ ); +}; diff --git a/webapp/src/component/activity/groups/groupTypeComponents/CreateProjectActivityGroup.tsx b/webapp/src/component/activity/groups/groupTypeComponents/CreateProjectActivityGroup.tsx new file mode 100644 index 0000000000..5409b4efd2 --- /dev/null +++ b/webapp/src/component/activity/groups/groupTypeComponents/CreateProjectActivityGroup.tsx @@ -0,0 +1,21 @@ +import React, { FC } from 'react'; +import { components } from 'tg.service/apiSchema.generated'; +import { CollapsibleActivityGroup } from './CollapsibleActivityGroup'; + +type Group = components['schemas']['ActivityGroupCreateProjectModel']; + +export const CreateProjectActivityGroup: FC<{ + group: Group; +}> = ({ group }) => { + return ( + } + > + {group.author?.name} Created project {group.data?.name} + + ); +}; + +const ExpandedContent: FC<{ group: Group }> = (props) => { + return
{JSON.stringify(props.group, null, 2)}
; +}; diff --git a/webapp/src/component/activity/types.tsx b/webapp/src/component/activity/types.tsx index 752e0bee92..a4da2c75de 100644 --- a/webapp/src/component/activity/types.tsx +++ b/webapp/src/component/activity/types.tsx @@ -78,7 +78,7 @@ export type FieldOptions = boolean | FieldOptionsObj; export type LanguageReferenceType = { tag: string; name: string; - flagEmoji: string; + flagEmoji?: string; }; export type KeyReferenceData = { diff --git a/webapp/src/component/languages/LanguageIconWithTooltip.tsx b/webapp/src/component/languages/LanguageIconWithTooltip.tsx new file mode 100644 index 0000000000..e290fed45e --- /dev/null +++ b/webapp/src/component/languages/LanguageIconWithTooltip.tsx @@ -0,0 +1,20 @@ +import React, { FC } from 'react'; +import { Tooltip } from '@mui/material'; +import { CircledLanguageIcon } from './CircledLanguageIcon'; +import { LanguageReferenceType } from '../activity/types'; + +type LanguageIconWithTooltipProps = { + l: LanguageReferenceType; +}; + +export const LanguageIconWithTooltip: FC = ({ + l, +}) => { + return ( + + + + + + ); +}; diff --git a/webapp/src/constants/links.tsx b/webapp/src/constants/links.tsx index 1cfc92610c..5ab44a5765 100644 --- a/webapp/src/constants/links.tsx +++ b/webapp/src/constants/links.tsx @@ -312,7 +312,7 @@ export class LINKS { 'websockets' ); - static ACTIVITY_PREVIEW = Link.ofParent(LINKS.PROJECT, 'activity'); + static PROJECT_ACTIVITY_GROUPS = Link.ofParent(LINKS.PROJECT, 'activity'); static PROJECT_DASHBOARD = LINKS.PROJECT; diff --git a/webapp/src/service/apiSchema.generated.ts b/webapp/src/service/apiSchema.generated.ts index f1d40fec74..f0ec151570 100644 --- a/webapp/src/service/apiSchema.generated.ts +++ b/webapp/src/service/apiSchema.generated.ts @@ -651,6 +651,9 @@ export interface paths { /** This endpoints returns the activity grouped by time windows so it's easier to read on the frontend. */ get: operations["getActivityGroups"]; }; + "/v2/projects/{projectId}/activity/group-items/create-key/{groupId}": { + get: operations["getCreateKeyItems"]; + }; "/v2/projects/{projectId}/activity": { get: operations["getActivity"]; }; @@ -1176,6 +1179,24 @@ export interface components { | "SERVER_ADMIN"; /** @description The user's permission type. This field is null if uses granular permissions */ type?: "NONE" | "VIEW" | "TRANSLATE" | "REVIEW" | "EDIT" | "MANAGE"; + /** + * @description List of languages user can translate to. If null, all languages editing is permitted. + * @example 200001,200004 + */ + translateLanguageIds?: number[]; + /** + * @description List of languages user can change state to. If null, changing state of all language values is permitted. + * @example 200001,200004 + */ + stateChangeLanguageIds?: number[]; + /** + * @deprecated + * @description Deprecated (use translateLanguageIds). + * + * List of languages current user has TRANSLATE permission to. If null, all languages edition is permitted. + * @example 200001,200004 + */ + permittedLanguageIds?: number[]; /** * @description Granted scopes to the user. When user has type permissions, this field contains permission scopes of the type. * @example KEYS_EDIT,TRANSLATIONS_VIEW @@ -1213,24 +1234,6 @@ export interface components { * @example 200001,200004 */ viewLanguageIds?: number[]; - /** - * @description List of languages user can translate to. If null, all languages editing is permitted. - * @example 200001,200004 - */ - translateLanguageIds?: number[]; - /** - * @description List of languages user can change state to. If null, changing state of all language values is permitted. - * @example 200001,200004 - */ - stateChangeLanguageIds?: number[]; - /** - * @deprecated - * @description Deprecated (use translateLanguageIds). - * - * List of languages current user has TRANSLATE permission to. If null, all languages edition is permitted. - * @example 200001,200004 - */ - permittedLanguageIds?: number[]; }; LanguageModel: { /** Format: int64 */ @@ -2036,7 +2039,7 @@ export interface components { /** Format: int64 */ id: number; username: string; - name?: string; + name: string; avatar?: components["schemas"]["Avatar"]; deleted: boolean; }; @@ -2197,15 +2200,15 @@ export interface components { token: string; /** Format: int64 */ id: number; + description: string; /** Format: int64 */ - createdAt: number; - /** Format: int64 */ - updatedAt: number; + expiresAt?: number; /** Format: int64 */ lastUsedAt?: number; /** Format: int64 */ - expiresAt?: number; - description: string; + createdAt: number; + /** Format: int64 */ + updatedAt: number; }; SetOrganizationRoleDto: { roleType: "MEMBER" | "OWNER"; @@ -2360,15 +2363,15 @@ export interface components { key: string; /** Format: int64 */ id: number; + username?: string; + description: string; scopes: string[]; /** Format: int64 */ - projectId: number; - username?: string; + expiresAt?: number; /** Format: int64 */ lastUsedAt?: number; /** Format: int64 */ - expiresAt?: number; - description: string; + projectId: number; projectName: string; userFullName?: string; }; @@ -3527,11 +3530,11 @@ export interface components { name: string; /** Format: int64 */ id: number; + /** @example This is a beautiful organization full of beautiful and clever people */ + description?: string; avatar?: components["schemas"]["Avatar"]; /** @example btforg */ slug: string; - /** @example This is a beautiful organization full of beautiful and clever people */ - description?: string; /** * @description The role of currently authorized user. * @@ -3675,9 +3678,9 @@ export interface components { name: string; /** Format: int64 */ id: number; - translation?: string; - description?: string; namespace?: string; + description?: string; + translation?: string; baseTranslation?: string; }; KeySearchSearchResultModel: { @@ -3685,9 +3688,9 @@ export interface components { name: string; /** Format: int64 */ id: number; - translation?: string; - description?: string; namespace?: string; + description?: string; + translation?: string; baseTranslation?: string; }; PagedModelKeySearchSearchResultModel: { @@ -4505,229 +4508,617 @@ export interface components { counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - PagedModelProjectActivityModel: { - _embedded?: { - activities?: components["schemas"]["ProjectActivityModel"][]; - }; - page?: components["schemas"]["PageMetadata"]; - }; - PagedModelTagModel: { - _embedded?: { - tags?: components["schemas"]["TagModel"][]; - }; - page?: components["schemas"]["PageMetadata"]; - }; - PagedModelBatchJobModel: { - _embedded?: { - batchJobs?: components["schemas"]["BatchJobModel"][]; - }; - page?: components["schemas"]["PageMetadata"]; - }; - CreditBalanceModel: { - /** Format: int64 */ - creditBalance: number; - /** Format: int64 */ - bucketSize: number; - /** Format: int64 */ - extraCreditBalance: number; - }; - CollectionModelKeyWithBaseTranslationModel: { - _embedded?: { - keys?: components["schemas"]["KeyWithBaseTranslationModel"][]; - }; - }; - KeyWithBaseTranslationModel: { - /** - * Format: int64 - * @description Id of key record - */ - id: number; - /** - * @description Name of key - * @example this_is_super_key - */ - name: string; - /** - * @description Namespace of key - * @example homepage - */ - namespace?: string; - /** - * @description Base translation - * @example This is translation - */ - baseTranslation?: string; - }; - ImportTranslationModel: { - /** Format: int64 */ - id: number; - text?: string; - keyName: string; - /** Format: int64 */ - keyId: number; - keyDescription?: string; - /** Format: int64 */ - conflictId?: number; - conflictText?: string; - override: boolean; - resolved: boolean; - isPlural: boolean; - existingKeyIsPlural: boolean; - }; - PagedModelImportTranslationModel: { - _embedded?: { - translations?: components["schemas"]["ImportTranslationModel"][]; - }; - page?: components["schemas"]["PageMetadata"]; - }; - ImportFileIssueModel: { - /** Format: int64 */ - id: number; - type: - | "KEY_IS_NOT_STRING" - | "MULTIPLE_VALUES_FOR_KEY_AND_LANGUAGE" - | "VALUE_IS_NOT_STRING" - | "KEY_IS_EMPTY" - | "VALUE_IS_EMPTY" - | "PO_MSGCTXT_NOT_SUPPORTED" - | "ID_ATTRIBUTE_NOT_PROVIDED" - | "TARGET_NOT_PROVIDED" - | "TRANSLATION_TOO_LONG" - | "KEY_IS_BLANK" - | "TRANSLATION_DEFINED_IN_ANOTHER_FILE" - | "INVALID_CUSTOM_VALUES"; - params: components["schemas"]["ImportFileIssueParamModel"][]; - }; - ImportFileIssueParamModel: { - type: - | "KEY_NAME" - | "KEY_ID" - | "LANGUAGE_ID" - | "KEY_INDEX" - | "VALUE" - | "LINE" - | "FILE_NODE_ORIGINAL" - | "LANGUAGE_NAME"; - value?: string; - }; - PagedModelImportFileIssueModel: { - _embedded?: { - importFileIssues?: components["schemas"]["ImportFileIssueModel"][]; - }; - page?: components["schemas"]["PageMetadata"]; - }; - CollectionModelImportNamespaceModel: { - _embedded?: { - namespaces?: components["schemas"]["ImportNamespaceModel"][]; - }; - }; - ImportNamespaceModel: { - /** - * Format: int64 - * @description The id of namespace. When null, namespace doesn't exist and will be created by import. - * @example 10000048 - */ - id?: number; - /** @example homepage */ - name: string; - }; - CollectionModelBatchJobModel: { - _embedded?: { - batchJobs?: components["schemas"]["BatchJobModel"][]; - }; - }; - PagedModelTranslationCommentModel: { - _embedded?: { - translationComments?: components["schemas"]["TranslationCommentModel"][]; - }; - page?: components["schemas"]["PageMetadata"]; - }; - PagedModelTranslationHistoryModel: { - _embedded?: { - revisions?: components["schemas"]["TranslationHistoryModel"][]; - }; - page?: components["schemas"]["PageMetadata"]; - }; - TranslationHistoryModel: { - /** @description Modified fields */ - modifications?: { - [key: string]: components["schemas"]["PropertyModification"]; - }; - /** - * Format: int64 - * @description Unix timestamp of the revision - */ - timestamp: number; - author?: components["schemas"]["SimpleUserAccountModel"]; - revisionType: "ADD" | "MOD" | "DEL"; - }; - SelectAllResponse: { - ids: number[]; - }; - KeyWithTranslationsModel: { - /** - * Format: int64 - * @description Id of key record - */ - keyId: number; - /** - * @description Name of key - * @example this_is_super_key - */ - keyName: string; - /** - * @description Is this key a plural? - * @example true - */ - keyIsPlural: boolean; - /** - * @description The placeholder name for plural parameter - * @example value - */ - keyPluralArgName?: string; - /** - * Format: int64 - * @description The namespace id of the key - * @example 100000282 - */ - keyNamespaceId?: number; - /** - * @description The namespace of the key - * @example homepage - */ - keyNamespace?: string; + ActivityGroupModel: + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "SET_TRANSLATION_STATE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "REVIEW"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "SET_TRANSLATIONS"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "DISMISS_AUTO_TRANSLATED_STATE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "SET_OUTDATED_FLAG"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "ADD_TRANSLATION_COMMENT"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "DELETE_TRANSLATION_COMMENT"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "EDIT_TRANSLATION_COMMENT"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "SET_TRANSLATION_COMMENT_STATE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "DELETE_SCREENSHOT"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "ADD_SCREENSHOT"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "EDIT_KEY_TAGS"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "EDIT_KEY_NAME"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "DELETE_KEY"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "CREATE_KEY"; + author?: components["schemas"]["SimpleUserAccountModel"]; + data?: { + /** Format: int32 */ + keyCount: number; + }; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "IMPORT"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "CREATE_LANGUAGE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "EDIT_LANGUAGE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "DELETE_LANGUAGE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "CREATE_PROJECT"; + author?: components["schemas"]["SimpleUserAccountModel"]; + data?: { + /** Format: int64 */ + id: number; + name: string; + languages: components["schemas"]["ActivityGroupLanguageModel"][]; + description?: string; + }; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "EDIT_PROJECT"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "NAMESPACE_EDIT"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_PRE_TRANSLATE_BY_TM"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_MACHINE_TRANSLATE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "AUTO_TRANSLATE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_CLEAR_TRANSLATIONS"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_COPY_TRANSLATIONS"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_SET_TRANSLATION_STATE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "CONTENT_DELIVERY_CONFIG_CREATE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "CONTENT_DELIVERY_CONFIG_UPDATE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "CONTENT_DELIVERY_CONFIG_DELETE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "CONTENT_STORAGE_CREATE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "CONTENT_STORAGE_UPDATE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "CONTENT_STORAGE_DELETE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "WEBHOOK_CONFIG_CREATE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "WEBHOOK_CONFIG_UPDATE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "WEBHOOK_CONFIG_DELETE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + }; + PagedModelActivityGroupModel: { + _embedded?: { + groups?: components["schemas"]["ActivityGroupModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; + CreateKeyGroupItemModel: { /** - * @description The namespace of the key - * @example homepage + * Format: int64 + * @description Id of key record */ - keyDescription?: string; - /** @description Tags of key */ - keyTags: components["schemas"]["TagModel"][]; + id: number; /** - * Format: int64 - * @description Count of screenshots provided for the key - * @example 1 + * @description Name of key + * @example this_is_super_key */ - screenshotCount: number; - /** @description Key screenshots. Not provided when API key hasn't screenshots.view scope permission. */ - screenshots?: components["schemas"]["ScreenshotModel"][]; - /** @description There is a context available for this key */ - contextPresent: boolean; + name: string; /** - * @description Translations object - * @example - * { - * "en": { - * "id": 100000003, - * "text": "This is super translation!" - * "state": "TRANSLATED", - * "commentCount": 1 - * } - * } + * @description Namespace of key + * @example homepage */ - translations: { - [key: string]: components["schemas"]["TranslationViewModel"]; - }; + namespace?: string; + /** @description If key is pluralized. If it will be reflected in the editor */ + isPlural: boolean; + /** @description The argument name for the plural */ + pluralArgName?: string; + /** @description The base translation value entered when key was created */ + baseTranslationValue?: string; + tags: string[]; + /** + * @description Description of key + * @example This key is used on homepage. It's a label of sign up button. + */ + description?: string; + /** @description Custom values of the key */ + custom?: { [key: string]: { [key: string]: unknown } }; + }; + PagedModelCreateKeyGroupItemModel: { + _embedded?: { + items?: components["schemas"]["CreateKeyGroupItemModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; + PagedModelProjectActivityModel: { + _embedded?: { + activities?: components["schemas"]["ProjectActivityModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; + PagedModelTagModel: { + _embedded?: { + tags?: components["schemas"]["TagModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; + PagedModelBatchJobModel: { + _embedded?: { + batchJobs?: components["schemas"]["BatchJobModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; + CreditBalanceModel: { + /** Format: int64 */ + creditBalance: number; + /** Format: int64 */ + bucketSize: number; + /** Format: int64 */ + extraCreditBalance: number; + }; + CollectionModelKeyWithBaseTranslationModel: { + _embedded?: { + keys?: components["schemas"]["KeyWithBaseTranslationModel"][]; + }; + }; + KeyWithBaseTranslationModel: { + /** + * Format: int64 + * @description Id of key record + */ + id: number; + /** + * @description Name of key + * @example this_is_super_key + */ + name: string; + /** + * @description Namespace of key + * @example homepage + */ + namespace?: string; + /** + * @description Base translation + * @example This is translation + */ + baseTranslation?: string; + }; + ImportTranslationModel: { + /** Format: int64 */ + id: number; + text?: string; + keyName: string; + /** Format: int64 */ + keyId: number; + keyDescription?: string; + /** Format: int64 */ + conflictId?: number; + conflictText?: string; + override: boolean; + resolved: boolean; + isPlural: boolean; + existingKeyIsPlural: boolean; + }; + PagedModelImportTranslationModel: { + _embedded?: { + translations?: components["schemas"]["ImportTranslationModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; + ImportFileIssueModel: { + /** Format: int64 */ + id: number; + type: + | "KEY_IS_NOT_STRING" + | "MULTIPLE_VALUES_FOR_KEY_AND_LANGUAGE" + | "VALUE_IS_NOT_STRING" + | "KEY_IS_EMPTY" + | "VALUE_IS_EMPTY" + | "PO_MSGCTXT_NOT_SUPPORTED" + | "ID_ATTRIBUTE_NOT_PROVIDED" + | "TARGET_NOT_PROVIDED" + | "TRANSLATION_TOO_LONG" + | "KEY_IS_BLANK" + | "TRANSLATION_DEFINED_IN_ANOTHER_FILE" + | "INVALID_CUSTOM_VALUES"; + params: components["schemas"]["ImportFileIssueParamModel"][]; + }; + ImportFileIssueParamModel: { + type: + | "KEY_NAME" + | "KEY_ID" + | "LANGUAGE_ID" + | "KEY_INDEX" + | "VALUE" + | "LINE" + | "FILE_NODE_ORIGINAL" + | "LANGUAGE_NAME"; + value?: string; + }; + PagedModelImportFileIssueModel: { + _embedded?: { + importFileIssues?: components["schemas"]["ImportFileIssueModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; + CollectionModelImportNamespaceModel: { + _embedded?: { + namespaces?: components["schemas"]["ImportNamespaceModel"][]; + }; + }; + ImportNamespaceModel: { + /** + * Format: int64 + * @description The id of namespace. When null, namespace doesn't exist and will be created by import. + * @example 10000048 + */ + id?: number; + /** @example homepage */ + name: string; + }; + CollectionModelBatchJobModel: { + _embedded?: { + batchJobs?: components["schemas"]["BatchJobModel"][]; + }; + }; + PagedModelTranslationCommentModel: { + _embedded?: { + translationComments?: components["schemas"]["TranslationCommentModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; + PagedModelTranslationHistoryModel: { + _embedded?: { + revisions?: components["schemas"]["TranslationHistoryModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; + TranslationHistoryModel: { + /** @description Modified fields */ + modifications?: { + [key: string]: components["schemas"]["PropertyModification"]; + }; + /** + * Format: int64 + * @description Unix timestamp of the revision + */ + timestamp: number; + author?: components["schemas"]["SimpleUserAccountModel"]; + revisionType: "ADD" | "MOD" | "DEL"; + }; + SelectAllResponse: { + ids: number[]; + }; + KeyWithTranslationsModel: { + /** + * Format: int64 + * @description Id of key record + */ + keyId: number; + /** + * @description Name of key + * @example this_is_super_key + */ + keyName: string; + /** + * @description Is this key a plural? + * @example true + */ + keyIsPlural: boolean; + /** + * @description The placeholder name for plural parameter + * @example value + */ + keyPluralArgName?: string; + /** + * Format: int64 + * @description The namespace id of the key + * @example 100000282 + */ + keyNamespaceId?: number; + /** + * @description The namespace of the key + * @example homepage + */ + keyNamespace?: string; + /** + * @description The namespace of the key + * @example homepage + */ + keyDescription?: string; + /** @description Tags of key */ + keyTags: components["schemas"]["TagModel"][]; + /** + * Format: int64 + * @description Count of screenshots provided for the key + * @example 1 + */ + screenshotCount: number; + /** @description Key screenshots. Not provided when API key hasn't screenshots.view scope permission. */ + screenshots?: components["schemas"]["ScreenshotModel"][]; + /** @description There is a context available for this key */ + contextPresent: boolean; + /** + * @description Translations object + * @example + * { + * "en": { + * "id": 100000003, + * "text": "This is super translation!" + * "state": "TRANSLATED", + * "commentCount": 1 + * } + * } + */ + translations: { + [key: string]: components["schemas"]["TranslationViewModel"]; + }; }; KeysWithTranslationsPageModel: { _embedded?: { @@ -4737,440 +5128,2259 @@ export interface components { /** @description Provided languages data */ selectedLanguages: components["schemas"]["LanguageModel"][]; /** - * @description Cursor to get next data - * @example eyJrZXlJZCI6eyJkaXJlY3Rpb24iOiJBU0MiLCJ2YWx1ZSI6IjEwMDAwMDAxMjAifX0= + * @description Cursor to get next data + * @example eyJrZXlJZCI6eyJkaXJlY3Rpb24iOiJBU0MiLCJ2YWx1ZSI6IjEwMDAwMDAxMjAifX0= + */ + nextCursor?: string; + }; + /** + * @description Translations object + * @example + * { + * "en": { + * "id": 100000003, + * "text": "This is super translation!" + * "state": "TRANSLATED", + * "commentCount": 1 + * } + * } + */ + TranslationViewModel: { + /** + * Format: int64 + * @description Id of translation record + */ + id: number; + /** @description Translation text */ + text?: string; + /** @description State of translation */ + state: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + /** @description Whether base language translation was changed after this translation was updated */ + outdated: boolean; + /** @description Was translated using Translation Memory or Machine translation service? */ + auto: boolean; + /** @description Which machine translation service was used to auto translate this */ + mtProvider?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE"; + /** + * Format: int64 + * @description Count of translation comments + */ + commentCount: number; + /** + * Format: int64 + * @description Count of unresolved translation comments + */ + unresolvedCommentCount: number; + /** @description Was translation memory used to translate this? */ + fromTranslationMemory: boolean; + }; + CollectionModelProjectTransferOptionModel: { + _embedded?: { + transferOptions?: components["schemas"]["ProjectTransferOptionModel"][]; + }; + }; + ProjectTransferOptionModel: { + name: string; + slug: string; + /** Format: int64 */ + id: number; + }; + LanguageStatsModel: { + /** Format: int64 */ + languageId?: number; + languageTag?: string; + languageName?: string; + languageOriginalName?: string; + languageFlagEmoji?: string; + /** Format: int64 */ + translatedKeyCount: number; + /** Format: int64 */ + translatedWordCount: number; + /** Format: double */ + translatedPercentage: number; + /** Format: int64 */ + reviewedKeyCount: number; + /** Format: int64 */ + reviewedWordCount: number; + /** Format: double */ + reviewedPercentage: number; + /** Format: int64 */ + untranslatedKeyCount: number; + /** Format: int64 */ + untranslatedWordCount: number; + /** Format: double */ + untranslatedPercentage: number; + }; + ProjectStatsModel: { + /** Format: int64 */ + projectId: number; + /** Format: int32 */ + languageCount: number; + /** Format: int64 */ + keyCount: number; + /** Format: int64 */ + baseWordsCount: number; + /** Format: double */ + translatedPercentage: number; + /** Format: double */ + reviewedPercentage: number; + /** Format: int64 */ + membersCount: number; + /** Format: int64 */ + tagCount: number; + languageStats: components["schemas"]["LanguageStatsModel"][]; + }; + PagedModelLanguageModel: { + _embedded?: { + languages?: components["schemas"]["LanguageModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; + CollectionModelLanguageAiPromptCustomizationModel: { + _embedded?: { + promptCustomizations?: components["schemas"]["LanguageAiPromptCustomizationModel"][]; + }; + }; + CollectionModelProjectInvitationModel: { + _embedded?: { + invitations?: components["schemas"]["ProjectInvitationModel"][]; + }; + }; + Pageable: { + /** Format: int32 */ + page?: number; + /** Format: int32 */ + size?: number; + sort?: string[]; + }; + PagedModelApiKeyModel: { + _embedded?: { + apiKeys?: components["schemas"]["ApiKeyModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; + PagedModelProjectWithStatsModel: { + _embedded?: { + projects?: components["schemas"]["ProjectWithStatsModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; + ProjectStatistics: { + /** Format: int64 */ + projectId: number; + /** Format: int64 */ + keyCount: number; + /** Format: int64 */ + languageCount: number; + translationStatePercentages: { [key: string]: number }; + }; + ProjectWithStatsModel: { + /** Format: int64 */ + id: number; + name: string; + description?: string; + slug?: string; + avatar?: components["schemas"]["Avatar"]; + organizationOwner?: components["schemas"]["SimpleOrganizationModel"]; + baseLanguage?: components["schemas"]["LanguageModel"]; + organizationRole?: "MEMBER" | "OWNER"; + directPermission?: components["schemas"]["PermissionModel"]; + computedPermission: components["schemas"]["ComputedPermissionModel"]; + stats: components["schemas"]["ProjectStatistics"]; + languages: components["schemas"]["LanguageModel"][]; + /** @description Whether to disable ICU placeholder visualization in the editor and it's support. */ + icuPlaceholders: boolean; + }; + CollectionModelScreenshotModel: { + _embedded?: { + screenshots?: components["schemas"]["ScreenshotModel"][]; + }; + }; + PagedModelPatModel: { + _embedded?: { + pats?: components["schemas"]["PatModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; + PatWithUserModel: { + user: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + description: string; + /** Format: int64 */ + expiresAt?: number; + /** Format: int64 */ + lastUsedAt?: number; + /** Format: int64 */ + createdAt: number; + /** Format: int64 */ + updatedAt: number; + }; + PagedModelOrganizationModel: { + _embedded?: { + organizations?: components["schemas"]["OrganizationModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; + CollectionModelOrganizationInvitationModel: { + _embedded?: { + organizationInvitations?: components["schemas"]["OrganizationInvitationModel"][]; + }; + }; + PublicUsageModel: { + /** Format: int64 */ + organizationId: number; + /** + * Format: int64 + * @description Current balance of standard credits. Standard credits are refilled every month + */ + creditBalance: number; + /** + * Format: int64 + * @description How many credits are included in your current plan + */ + includedMtCredits: number; + /** + * Format: int64 + * @description Date when credits were refilled. (In epoch format) + */ + creditBalanceRefilledAt: number; + /** + * Format: int64 + * @description Date when credits will be refilled. (In epoch format) + */ + creditBalanceNextRefillAt: number; + /** + * Format: int64 + * @description Currently used credits over credits included in plan and extra credits + */ + currentPayAsYouGoMtCredits: number; + /** + * Format: int64 + * @description The maximum amount organization can spend on MT credit usage before they reach the spending limit + */ + availablePayAsYouGoMtCredits: number; + /** + * Format: int64 + * @description Extra credits, which are neither refilled nor reset every month. These credits are used when there are no standard credits + */ + extraCreditBalance: number; + /** + * Format: int64 + * @description How many translations can be stored within your organization + */ + translationSlotsLimit: number; + /** + * Format: int64 + * @description How many translation slots are included in current subscription plan. How many translation slots can organization use without additional costs + */ + includedTranslationSlots: number; + /** + * Format: int64 + * @description How many translations are included in current subscription plan. How many translations can organization use without additional costs + */ + includedTranslations: number; + /** + * Format: int64 + * @description How many translations slots are currently used by organization + */ + currentTranslationSlots: number; + /** + * Format: int64 + * @description How many non-empty translations are currently stored by organization + */ + currentTranslations: number; + /** + * Format: int64 + * @description How many translations can be stored until reaching the limit. (For pay us you go, the top limit is the spending limit) + */ + translationsLimit: number; + }; + CollectionModelWorkspaceModel: { + _embedded?: { + workspaces?: components["schemas"]["WorkspaceModel"][]; + }; + }; + WorkspaceModel: { + /** Format: int64 */ + id: number; + slackTeamName: string; + slackTeamId: string; + }; + ConnectToSlackUrlModel: { + url: string; + }; + PagedModelUserAccountWithOrganizationRoleModel: { + _embedded?: { + usersInOrganization?: components["schemas"]["UserAccountWithOrganizationRoleModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; + SimpleProjectModel: { + /** Format: int64 */ + id: number; + name: string; + description?: string; + slug?: string; + avatar?: components["schemas"]["Avatar"]; + baseLanguage?: components["schemas"]["LanguageModel"]; + icuPlaceholders: boolean; + }; + UserAccountWithOrganizationRoleModel: { + /** Format: int64 */ + id: number; + name: string; + username: string; + organizationRole?: "MEMBER" | "OWNER"; + projectsWithDirectPermission: components["schemas"]["SimpleProjectModel"][]; + avatar?: components["schemas"]["Avatar"]; + }; + SimpleModifiedEntityView: { + entityClass: string; + /** Format: int64 */ + entityId: number; + exists?: boolean; + modifications: { + [key: string]: components["schemas"]["PropertyModification"]; + }; + description?: { [key: string]: { [key: string]: unknown } }; + describingRelations?: { + [key: string]: components["schemas"]["ExistenceEntityDescription"]; + }; + }; + UserNotificationModel: { + /** Format: int64 */ + id: number; + type: + | "ACTIVITY_LANGUAGES_CREATED" + | "ACTIVITY_KEYS_CREATED" + | "ACTIVITY_KEYS_UPDATED" + | "ACTIVITY_KEYS_SCREENSHOTS_UPLOADED" + | "ACTIVITY_SOURCE_STRINGS_UPDATED" + | "ACTIVITY_TRANSLATIONS_UPDATED" + | "ACTIVITY_TRANSLATION_OUTDATED" + | "ACTIVITY_TRANSLATION_REVIEWED" + | "ACTIVITY_TRANSLATION_UNREVIEWED" + | "ACTIVITY_NEW_COMMENTS" + | "ACTIVITY_COMMENTS_MENTION" + | "BATCH_JOB_ERRORED"; + project?: components["schemas"]["SimpleProjectModel"]; + batchJob?: components["schemas"]["BatchJobModel"]; + modifiedEntities?: components["schemas"]["SimpleModifiedEntityView"][]; + unread: boolean; + /** Format: date-time */ + markedDoneAt?: string; + /** Format: date-time */ + lastUpdated: string; + }; + ApiKeyWithLanguagesModel: { + /** + * @deprecated + * @description Languages for which user has translate permission. + */ + permittedLanguageIds?: number[]; + /** Format: int64 */ + id: number; + username?: string; + description: string; + scopes: string[]; + /** Format: int64 */ + expiresAt?: number; + /** Format: int64 */ + lastUsedAt?: number; + /** Format: int64 */ + projectId: number; + projectName: string; + userFullName?: string; + }; + PagedModelUserAccountModel: { + _embedded?: { + users?: components["schemas"]["UserAccountModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; + UserAccountModel: { + /** Format: int64 */ + id: number; + username: string; + name?: string; + emailAwaitingVerification?: string; + avatar?: components["schemas"]["Avatar"]; + globalServerRole: "USER" | "ADMIN"; + deleted: boolean; + disabled: boolean; + }; + UserTotpDisableRequestDto: { + password: string; + }; + DeleteKeysDto: { + /** @description IDs of keys to delete */ + ids: number[]; + }; + ActivityDescribingEntity: { + activityRevision: components["schemas"]["ActivityRevision"]; + entityClass: string; + /** Format: int64 */ + entityId: number; + data: { [key: string]: { [key: string]: unknown } }; + describingRelations?: { + [key: string]: components["schemas"]["EntityDescriptionRef"]; + }; + }; + ActivityGroup: { + type: + | "SET_TRANSLATION_STATE" + | "REVIEW" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "ADD_TRANSLATION_COMMENT" + | "DELETE_TRANSLATION_COMMENT" + | "EDIT_TRANSLATION_COMMENT" + | "SET_TRANSLATION_COMMENT_STATE" + | "DELETE_SCREENSHOT" + | "ADD_SCREENSHOT" + | "EDIT_KEY_TAGS" + | "EDIT_KEY_NAME" + | "DELETE_KEY" + | "CREATE_KEY" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + /** Format: int64 */ + id: number; + /** Format: int64 */ + authorId?: number; + /** Format: int64 */ + projectId?: number; + activityRevisions: components["schemas"]["ActivityRevision"][]; + }; + ActivityModifiedEntity: { + activityRevision: components["schemas"]["ActivityRevision"]; + entityClass: string; + /** Format: int64 */ + entityId: number; + modifications: { + [key: string]: components["schemas"]["PropertyModification"]; + }; + describingData?: { [key: string]: { [key: string]: unknown } }; + describingRelations?: { + [key: string]: components["schemas"]["EntityDescriptionRef"]; + }; + revisionType: "ADD" | "MOD" | "DEL"; + }; + ActivityRevision: { + /** Format: int64 */ + id: number; + /** Format: date-time */ + timestamp: string; + /** Format: int64 */ + authorId?: number; + meta?: { [key: string]: { [key: string]: unknown } }; + type?: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "HARD_DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE" + | "COMPLEX_TAG_OPERATION"; + /** Format: int64 */ + projectId?: number; + describingRelations: components["schemas"]["ActivityDescribingEntity"][]; + modifiedEntities: components["schemas"]["ActivityModifiedEntity"][]; + batchJobChunkExecution?: components["schemas"]["BatchJobChunkExecution"]; + batchJob?: components["schemas"]["BatchJob"]; + activityGroups: components["schemas"]["ActivityGroup"][]; + isInitializedByInterceptor: boolean; + /** Format: int32 */ + cancelledBatchJobExecutionCount?: number; + }; + ApiKey: { + key?: string; + scopesEnum: ( + | "translations.view" + | "translations.edit" + | "keys.edit" + | "screenshots.upload" + | "screenshots.delete" + | "screenshots.view" + | "activity.view" + | "languages.edit" + | "admin" + | "project.edit" + | "members.view" + | "members.edit" + | "translation-comments.add" + | "translation-comments.edit" + | "translation-comments.set-state" + | "translations.state-edit" + | "keys.view" + | "keys.delete" + | "keys.create" + | "batch-jobs.view" + | "batch-jobs.cancel" + | "translations.batch-by-tm" + | "translations.batch-machine" + | "content-delivery.manage" + | "content-delivery.publish" + | "webhooks.manage" + )[]; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + description: string; + keyHash: string; + userAccount: components["schemas"]["UserAccount"]; + project: components["schemas"]["Project"]; + /** Format: date-time */ + expiresAt?: string; + /** Format: date-time */ + lastUsedAt?: string; + encodedKey?: string; + disableActivityLogging: boolean; + }; + AutoTranslationConfig: { + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + project: components["schemas"]["Project"]; + targetLanguage?: components["schemas"]["Language"]; + usingTm: boolean; + usingPrimaryMtService: boolean; + enableForImport: boolean; + disableActivityLogging: boolean; + }; + Automation: { + project: components["schemas"]["Project"]; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + triggers: components["schemas"]["AutomationTrigger"][]; + actions: components["schemas"]["AutomationAction"][]; + disableActivityLogging: boolean; + }; + AutomationAction: { + automation: components["schemas"]["Automation"]; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + type: "CONTENT_DELIVERY_PUBLISH" | "WEBHOOK" | "SLACK_SUBSCRIPTION"; + contentDeliveryConfig?: components["schemas"]["ContentDeliveryConfig"]; + webhookConfig?: components["schemas"]["WebhookConfig"]; + slackConfig?: components["schemas"]["SlackConfig"]; + disableActivityLogging: boolean; + }; + AutomationTrigger: { + automation: components["schemas"]["Automation"]; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + type: "TRANSLATION_DATA_MODIFICATION" | "ACTIVITY"; + activityType?: + | "UNKNOWN" + | "SET_TRANSLATION_STATE" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "TRANSLATION_COMMENT_ADD" + | "TRANSLATION_COMMENT_DELETE" + | "TRANSLATION_COMMENT_EDIT" + | "TRANSLATION_COMMENT_SET_STATE" + | "SCREENSHOT_DELETE" + | "SCREENSHOT_ADD" + | "KEY_TAGS_EDIT" + | "KEY_NAME_EDIT" + | "KEY_DELETE" + | "CREATE_KEY" + | "COMPLEX_EDIT" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "HARD_DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "BATCH_TAG_KEYS" + | "BATCH_UNTAG_KEYS" + | "BATCH_SET_KEYS_NAMESPACE" + | "AUTOMATION" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE" + | "COMPLEX_TAG_OPERATION"; + /** Format: int64 */ + debounceDurationInMs?: number; + disableActivityLogging: boolean; + }; + AzureContentStorageConfig: { + contentStorage: components["schemas"]["ContentStorage"]; + connectionString: string; + containerName: string; + }; + BatchJob: { + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + project: components["schemas"]["Project"]; + author?: components["schemas"]["UserAccount"]; + target: { [key: string]: unknown }[]; + /** Format: int32 */ + totalItems: number; + /** Format: int32 */ + totalChunks: number; + /** Format: int32 */ + chunkSize: number; + status: + | "PENDING" + | "RUNNING" + | "SUCCESS" + | "FAILED" + | "CANCELLED" + | "DEBOUNCED"; + type: + | "PRE_TRANSLATE_BT_TM" + | "MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "DELETE_KEYS" + | "SET_TRANSLATIONS_STATE" + | "CLEAR_TRANSLATIONS" + | "COPY_TRANSLATIONS" + | "TAG_KEYS" + | "UNTAG_KEYS" + | "SET_KEYS_NAMESPACE" + | "AUTOMATION"; + activityRevision?: components["schemas"]["ActivityRevision"]; + params?: { [key: string]: unknown }; + /** Format: int32 */ + maxPerJobConcurrency: number; + jobCharacter: "SLOW" | "FAST"; + hidden: boolean; + /** Format: int64 */ + debounceDurationInMs?: number; + /** Format: int64 */ + debounceMaxWaitTimeInMs?: number; + /** Format: date-time */ + lastDebouncingEvent?: string; + debouncingKey?: string; + dto: components["schemas"]["BatchJobDto"]; + chunkedTarget: { [key: string]: unknown }[][]; + disableActivityLogging: boolean; + }; + BatchJobChunkExecution: { + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + batchJob: components["schemas"]["BatchJob"]; + status: "PENDING" | "RUNNING" | "SUCCESS" | "FAILED" | "CANCELLED"; + /** Format: int32 */ + chunkNumber: number; + successTargets: { [key: string]: unknown }[]; + stackTrace?: string; + errorKey?: string; + errorMessage?: + | "unauthenticated" + | "api_access_forbidden" + | "api_key_not_found" + | "invalid_api_key" + | "invalid_project_api_key" + | "project_api_key_expired" + | "bad_credentials" + | "mfa_enabled" + | "invalid_otp_code" + | "mfa_not_enabled" + | "can_not_revoke_own_permissions" + | "data_corrupted" + | "invitation_code_does_not_exist_or_expired" + | "language_tag_exists" + | "language_name_exists" + | "language_not_found" + | "operation_not_permitted" + | "registrations_not_allowed" + | "project_not_found" + | "resource_not_found" + | "scope_not_found" + | "key_exists" + | "third_party_auth_error_message" + | "third_party_auth_no_email" + | "third_party_auth_no_sub" + | "third_party_auth_unknown_error" + | "email_already_verified" + | "third_party_unauthorized" + | "third_party_google_workspace_mismatch" + | "username_already_exists" + | "username_or_password_invalid" + | "user_already_has_permissions" + | "user_already_has_role" + | "user_not_found" + | "file_not_image" + | "file_too_big" + | "invalid_timestamp" + | "email_not_verified" + | "missing_callback_url" + | "invalid_jwt_token" + | "expired_jwt_token" + | "general_jwt_error" + | "cannot_find_suitable_address_part" + | "address_part_not_unique" + | "user_is_not_member_of_organization" + | "organization_has_no_other_owner" + | "user_has_no_project_access" + | "user_is_organization_owner" + | "cannot_set_your_own_permissions" + | "user_is_organization_member" + | "property_not_mutable" + | "import_language_not_from_project" + | "existing_language_not_selected" + | "conflict_is_not_resolved" + | "language_already_selected" + | "cannot_parse_file" + | "could_not_resolve_property" + | "cannot_add_more_then_100_languages" + | "no_languages_provided" + | "language_with_base_language_tag_not_found" + | "language_not_from_project" + | "namespace_not_from_project" + | "cannot_delete_base_language" + | "key_not_from_project" + | "max_screenshots_exceeded" + | "translation_not_from_project" + | "can_edit_only_own_comment" + | "request_parse_error" + | "filter_by_value_state_not_valid" + | "import_has_expired" + | "tag_not_from_project" + | "translation_text_too_long" + | "invalid_recaptcha_token" + | "cannot_leave_owning_project" + | "cannot_leave_project_with_organization_role" + | "dont_have_direct_permissions" + | "tag_too_log" + | "too_many_uploaded_images" + | "one_or_more_images_not_found" + | "screenshot_not_of_key" + | "service_not_found" + | "too_many_requests" + | "translation_not_found" + | "out_of_credits" + | "key_not_found" + | "organization_not_found" + | "cannot_find_base_language" + | "base_language_not_found" + | "no_exported_result" + | "cannot_set_your_own_role" + | "only_translate_review_or_view_permission_accepts_view_languages" + | "oauth2_token_url_not_set" + | "oauth2_user_url_not_set" + | "email_already_invited_or_member" + | "price_not_found" + | "invoice_not_from_organization" + | "invoice_not_found" + | "plan_not_found" + | "plan_not_available_any_more" + | "no_auto_translation_method" + | "cannot_translate_base_language" + | "pat_not_found" + | "invalid_pat" + | "pat_expired" + | "operation_unavailable_for_account_type" + | "validation_email_is_not_valid" + | "current_password_required" + | "cannot_create_organization" + | "wrong_current_password" + | "wrong_param_type" + | "expired_super_jwt_token" + | "cannot_delete_your_own_account" + | "cannot_sort_by_this_column" + | "namespace_not_found" + | "namespace_exists" + | "invalid_authentication_method" + | "unknown_sort_property" + | "only_review_permission_accepts_state_change_languages" + | "only_translate_or_review_permission_accepts_translate_languages" + | "cannot_set_language_permissions_for_admin_scope" + | "cannot_set_view_languages_without_translations_view_scope" + | "cannot_set_translate_languages_without_translations_edit_scope" + | "cannot_set_state_change_languages_without_translations_state_edit_scope" + | "language_not_permitted" + | "scopes_has_to_be_set" + | "set_exactly_one_of_scopes_or_type" + | "translation_exists" + | "import_keys_error" + | "provide_only_one_of_screenshots_and_screenshot_uploaded_image_ids" + | "multiple_projects_not_supported" + | "plan_translation_limit_exceeded" + | "feature_not_enabled" + | "license_key_not_found" + | "cannot_set_view_languages_without_for_level_based_permissions" + | "cannot_set_different_translate_and_state_change_languages_for_level_based_permissions" + | "cannot_disable_your_own_account" + | "subscription_not_found" + | "invoice_does_not_have_usage" + | "customer_not_found" + | "subscription_not_active" + | "organization_already_subscribed" + | "organization_not_subscribed" + | "license_key_used_by_another_instance" + | "translation_spending_limit_exceeded" + | "credit_spending_limit_exceeded" + | "seats_spending_limit_exceeded" + | "this_instance_is_already_licensed" + | "big_meta_not_from_project" + | "mt_service_not_enabled" + | "project_not_selected" + | "organization_not_selected" + | "plan_has_subscribers" + | "translation_failed" + | "batch_job_not_found" + | "key_exists_in_namespace" + | "tag_is_blank" + | "execution_failed_on_management_error" + | "translation_api_rate_limit" + | "cannot_finalize_activity" + | "formality_not_supported_by_service" + | "language_not_supported_by_service" + | "rate_limited" + | "pat_access_not_allowed" + | "pak_access_not_allowed" + | "cannot_modify_disabled_translation" + | "azure_config_required" + | "s3_config_required" + | "content_storage_config_required" + | "content_storage_test_failed" + | "content_storage_config_invalid" + | "invalid_connection_string" + | "cannot_create_azure_storage_client" + | "s3_access_key_required" + | "azure_connection_string_required" + | "s3_secret_key_required" + | "cannot_store_file_to_content_storage" + | "unexpected_error_while_publishing_to_content_storage" + | "webhook_responded_with_non_200_status" + | "unexpected_error_while_executing_webhook" + | "content_storage_is_in_use" + | "cannot_set_state_for_missing_translation" + | "no_project_id_provided" + | "license_key_not_provided" + | "subscription_already_canceled" + | "user_is_subscribed_to_paid_plan" + | "cannot_create_free_plan_without_fixed_type" + | "cannot_modify_plan_free_status" + | "key_id_not_provided" + | "free_self_hosted_seat_limit_exceeded" + | "advanced_params_not_supported" + | "plural_forms_not_found_for_language" + | "nested_plurals_not_supported" + | "message_is_not_plural" + | "content_outside_plural_forms" + | "invalid_plural_form" + | "multiple_plurals_not_supported" + | "custom_values_json_too_long" + | "unsupported_po_message_format" + | "plural_forms_data_loss" + | "current_user_does_not_own_image" + | "user_cannot_view_this_organization" + | "user_is_not_owner_of_organization" + | "pak_created_for_different_project" + | "custom_slug_is_only_applicable_for_custom_storage" + | "invalid_slug_format" + | "batch_job_cancellation_timeout" + | "import_failed" + | "cannot_add_more_then_1000_languages" + | "no_data_to_import" + | "multiple_namespaces_mapped_to_single_file" + | "multiple_mappings_for_same_file_language_name" + | "multiple_mappings_for_null_file_language_name" + | "too_many_mappings_for_file" + | "missing_placeholder_in_template" + | "tag_not_found" + | "cannot_parse_encrypted_slack_login_data" + | "slack_workspace_not_found" + | "cannot_fetch_user_details_from_slack" + | "slack_missing_scope" + | "slack_not_connected_to_your_account" + | "slack_invalid_command" + | "slack_not_subscribed_yet" + | "slack_connection_failed" + | "tolgee_account_already_connected" + | "slack_not_configured" + | "slack_workspace_already_connected" + | "slack_connection_error" + | "email_verification_code_not_valid"; + /** Format: date-time */ + executeAfter?: string; + retry: boolean; + activityRevision?: components["schemas"]["ActivityRevision"]; + disableActivityLogging: boolean; + }; + BatchJobDto: { + /** Format: int64 */ + id: number; + /** Format: int64 */ + projectId: number; + /** Format: int64 */ + authorId?: number; + target: { [key: string]: unknown }[]; + /** Format: int32 */ + totalItems: number; + /** Format: int32 */ + totalChunks: number; + /** Format: int32 */ + chunkSize: number; + status: + | "PENDING" + | "RUNNING" + | "SUCCESS" + | "FAILED" + | "CANCELLED" + | "DEBOUNCED"; + type: + | "PRE_TRANSLATE_BT_TM" + | "MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "DELETE_KEYS" + | "SET_TRANSLATIONS_STATE" + | "CLEAR_TRANSLATIONS" + | "COPY_TRANSLATIONS" + | "TAG_KEYS" + | "UNTAG_KEYS" + | "SET_KEYS_NAMESPACE" + | "AUTOMATION"; + params?: { [key: string]: unknown }; + /** Format: int32 */ + maxPerJobConcurrency: number; + jobCharacter: "SLOW" | "FAST"; + hidden: boolean; + debouncingKey?: string; + /** Format: int64 */ + createdAt?: number; + /** Format: int64 */ + lastDebouncingEvent?: number; + /** Format: int64 */ + debounceDurationInMs?: number; + /** Format: int64 */ + debounceMaxWaitTimeInMs?: number; + chunkedTarget: { [key: string]: unknown }[][]; + }; + ContentDeliveryConfig: { + project: components["schemas"]["Project"]; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + name: string; + slug: string; + customSlug: boolean; + contentStorage?: components["schemas"]["ContentStorage"]; + automationActions: components["schemas"]["AutomationAction"][]; + /** Format: date-time */ + lastPublished?: string; + pruneBeforePublish: boolean; + /** + * @description Languages to be contained in export. + * + * If null, all languages are exported + * @example en + */ + languages?: string[]; + /** @description Format to export to */ + format: + | "JSON" + | "JSON_TOLGEE" + | "XLIFF" + | "PO" + | "APPLE_STRINGS_STRINGSDICT" + | "APPLE_XLIFF" + | "ANDROID_XML" + | "FLUTTER_ARB" + | "PROPERTIES" + | "YAML_RUBY" + | "YAML"; + /** + * @description Delimiter to structure file content. + * + * e.g. For key "home.header.title" would result in {"home": {"header": "title": {"Hello"}}} structure. + * + * When null, resulting file won't be structured. Works only for generic structured formats (e.g. JSON, YAML), + * specific formats like `YAML_RUBY` don't honor this parameter. + */ + structureDelimiter?: string; + /** + * @description If true, for structured formats (like JSON) arrays are supported. + * + * e.g. Key hello[0] will be exported as {"hello": ["..."]} */ - nextCursor?: string; - }; - /** - * @description Translations object - * @example - * { - * "en": { - * "id": 100000003, - * "text": "This is super translation!" - * "state": "TRANSLATED", - * "commentCount": 1 - * } - * } - */ - TranslationViewModel: { + supportArrays: boolean; + /** @description Filter key IDs to be contained in export */ + filterKeyId?: number[]; + /** @description Filter key IDs not to be contained in export */ + filterKeyIdNot?: number[]; /** - * Format: int64 - * @description Id of translation record + * @description Filter keys tagged by. + * + * This filter works the same as `filterTagIn` but in this cases it accepts single tag only. */ - id: number; - /** @description Translation text */ - text?: string; - /** @description State of translation */ - state: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; - /** @description Whether base language translation was changed after this translation was updated */ - outdated: boolean; - /** @description Was translated using Translation Memory or Machine translation service? */ - auto: boolean; - /** @description Which machine translation service was used to auto translate this */ - mtProvider?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE"; + filterTag?: string; + /** @description Filter keys tagged by one of provided tags */ + filterTagIn?: string[]; + /** @description Filter keys not tagged by one of provided tags */ + filterTagNotIn?: string[]; + /** @description Filter keys with prefix */ + filterKeyPrefix?: string; + /** @description Filter translations with state. By default, all states except untranslated is exported. */ + filterState?: ("UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED")[]; + /** @description Filter translations with namespace. By default, all namespaces everything are exported. To export default namespace, use empty string. */ + filterNamespace?: string[]; /** - * Format: int64 - * @description Count of translation comments + * @description Message format to be used for export. + * + * e.g. PHP_PO: Hello %s, ICU: Hello {name}. + * + * This property is honored only for generic formats like JSON or YAML. + * For specific formats like `YAML_RUBY` it's ignored. */ - commentCount: number; + messageFormat?: + | "C_SPRINTF" + | "PHP_SPRINTF" + | "JAVA_STRING_FORMAT" + | "APPLE_SPRINTF" + | "RUBY_SPRINTF" + | "ICU"; /** - * Format: int64 - * @description Count of unresolved translation comments + * @description This is a template that defines the structure of the resulting .zip file content. + * + * The template is a string that can contain the following placeholders: {namespace}, {languageTag}, + * {androidLanguageTag}, {snakeLanguageTag}, {extension}. + * + * For example, when exporting to JSON with the template `{namespace}/{languageTag}.{extension}`, + * the English translations of the `home` namespace will be stored in `home/en.json`. + * + * The `{snakeLanguageTag}` placeholder is the same as `{languageTag}` but in snake case. (e.g., en_US). + * + * The Android specific `{androidLanguageTag}` placeholder is the same as `{languageTag}` + * but in Android format. (e.g., en-rUS) */ - unresolvedCommentCount: number; - /** @description Was translation memory used to translate this? */ - fromTranslationMemory: boolean; + fileStructureTemplate?: string; + disableActivityLogging: boolean; }; - CollectionModelProjectTransferOptionModel: { - _embedded?: { - transferOptions?: components["schemas"]["ProjectTransferOptionModel"][]; - }; + ContentStorage: { + project: components["schemas"]["Project"]; + name: string; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + publicUrlPrefix?: string; + azureContentStorageConfig?: components["schemas"]["AzureContentStorageConfig"]; + s3ContentStorageConfig?: components["schemas"]["S3ContentStorageConfig"]; + configs: components["schemas"]["StorageConfig"][]; + storageConfig?: components["schemas"]["StorageConfig"]; + disableActivityLogging: boolean; + }; + EmailVerification: { + /** Format: int64 */ + id?: number; + code: string; + newEmail?: string; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + userAccount: components["schemas"]["UserAccount"]; + }; + EntityDescriptionRef: { + entityClass: string; + /** Format: int64 */ + entityId: number; + }; + Import: { + project: components["schemas"]["Project"]; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + author: components["schemas"]["UserAccount"]; + files: components["schemas"]["ImportFile"][]; + /** Format: date-time */ + deletedAt?: string; + disableActivityLogging: boolean; + }; + ImportFile: { + name?: string; + import: components["schemas"]["Import"]; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + issues: components["schemas"]["ImportFileIssue"][]; + keys: components["schemas"]["ImportKey"][]; + languages: components["schemas"]["ImportLanguage"][]; + namespace?: string; + needsParamConversion: boolean; + disableActivityLogging: boolean; + }; + ImportFileIssue: { + file: components["schemas"]["ImportFile"]; + type: + | "KEY_IS_NOT_STRING" + | "MULTIPLE_VALUES_FOR_KEY_AND_LANGUAGE" + | "VALUE_IS_NOT_STRING" + | "KEY_IS_EMPTY" + | "VALUE_IS_EMPTY" + | "PO_MSGCTXT_NOT_SUPPORTED" + | "ID_ATTRIBUTE_NOT_PROVIDED" + | "TARGET_NOT_PROVIDED" + | "TRANSLATION_TOO_LONG" + | "KEY_IS_BLANK" + | "TRANSLATION_DEFINED_IN_ANOTHER_FILE" + | "INVALID_CUSTOM_VALUES"; + params: components["schemas"]["ImportFileIssueParam"][]; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + disableActivityLogging: boolean; + }; + ImportFileIssueParam: { + issue: components["schemas"]["ImportFileIssue"]; + type: + | "KEY_NAME" + | "KEY_ID" + | "LANGUAGE_ID" + | "KEY_INDEX" + | "VALUE" + | "LINE" + | "FILE_NODE_ORIGINAL" + | "LANGUAGE_NAME"; + value: string; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + disableActivityLogging: boolean; + }; + ImportKey: { + name: string; + file: components["schemas"]["ImportFile"]; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + translations: components["schemas"]["ImportTranslation"][]; + keyMeta?: components["schemas"]["KeyMeta"]; + pluralArgName?: string; + disableActivityLogging: boolean; + }; + ImportLanguage: { + name: string; + file: components["schemas"]["ImportFile"]; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + translations: components["schemas"]["ImportTranslation"][]; + existingLanguage?: components["schemas"]["Language"]; + disableActivityLogging: boolean; + }; + ImportTranslation: { + text?: string; + language: components["schemas"]["ImportLanguage"]; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + key: components["schemas"]["ImportKey"]; + conflict?: components["schemas"]["Translation"]; + override: boolean; + resolvedHash?: string; + isSelectedToImport: boolean; + isPlural: boolean; + rawData?: { [key: string]: unknown }; + convertor?: + | "JSON_ICU" + | "JSON_JAVA" + | "JSON_PHP" + | "JSON_RUBY" + | "JSON_C" + | "PO_PHP" + | "PO_C" + | "PO_JAVA" + | "PO_ICU" + | "PO_RUBY" + | "STRINGS" + | "STRINGSDICT" + | "APPLE_XLIFF" + | "PROPERTIES_ICU" + | "PROPERTIES_JAVA" + | "PROPERTIES_UNKNOWN" + | "ANDROID_XML" + | "FLUTTER_ARB" + | "YAML_RUBY" + | "YAML_JAVA" + | "YAML_ICU" + | "YAML_PHP" + | "YAML_UNKNOWN" + | "XLIFF_ICU" + | "XLIFF_JAVA" + | "XLIFF_PHP" + | "XLIFF_RUBY"; + resolved: boolean; + disableActivityLogging: boolean; + }; + Invitation: { + /** Format: int64 */ + id?: number; + code: string; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + permission?: components["schemas"]["Permission"]; + organizationRole?: components["schemas"]["OrganizationRole"]; + name?: string; + email?: string; + }; + Key: { + name: string; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + project: components["schemas"]["Project"]; + namespace?: components["schemas"]["Namespace"]; + translations: components["schemas"]["Translation"][]; + keyMeta?: components["schemas"]["KeyMeta"]; + keyScreenshotReferences: components["schemas"]["KeyScreenshotReference"][]; + isPlural: boolean; + pluralArgName?: string; + disableActivityLogging: boolean; + }; + KeyCodeReference: { + keyMeta: components["schemas"]["KeyMeta"]; + author: components["schemas"]["UserAccount"]; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + path: string; + /** Format: int64 */ + line?: number; + fromImport: boolean; + disableActivityLogging: boolean; + }; + KeyComment: { + keyMeta: components["schemas"]["KeyMeta"]; + author: components["schemas"]["UserAccount"]; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + fromImport: boolean; + text: string; + disableActivityLogging: boolean; + }; + KeyMeta: { + key?: components["schemas"]["Key"]; + importKey?: components["schemas"]["ImportKey"]; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + comments: components["schemas"]["KeyComment"][]; + codeReferences: components["schemas"]["KeyCodeReference"][]; + tags: components["schemas"]["Tag"][]; + description?: string; + custom?: { [key: string]: { [key: string]: unknown } }; + disableActivityLogging: boolean; }; - ProjectTransferOptionModel: { - name: string; - slug: string; + KeyScreenshotReference: { + key: components["schemas"]["Key"]; + screenshot: components["schemas"]["Screenshot"]; + positions?: components["schemas"]["KeyInScreenshotPosition"][]; + originalText?: string; + }; + Language: { + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; /** Format: int64 */ id: number; + translations: components["schemas"]["Translation"][]; + project: components["schemas"]["Project"]; + tag: string; + name: string; + originalName?: string; + flagEmoji?: string; + mtServiceConfig?: components["schemas"]["MtServiceConfig"]; + autoTranslationConfig?: components["schemas"]["AutoTranslationConfig"]; + stats?: components["schemas"]["LanguageStats"]; + aiTranslatorPromptDescription?: string; + /** Format: date-time */ + deletedAt?: string; + disableActivityLogging: boolean; }; - LanguageStatsModel: { + LanguageStats: { + language: components["schemas"]["Language"]; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; /** Format: int64 */ - languageId?: number; - languageTag?: string; - languageName?: string; - languageOriginalName?: string; - languageFlagEmoji?: string; + id: number; /** Format: int64 */ - translatedKeyCount: number; + untranslatedWords: number; /** Format: int64 */ - translatedWordCount: number; - /** Format: double */ - translatedPercentage: number; + translatedWords: number; /** Format: int64 */ - reviewedKeyCount: number; + reviewedWords: number; /** Format: int64 */ - reviewedWordCount: number; - /** Format: double */ - reviewedPercentage: number; + untranslatedKeys: number; /** Format: int64 */ - untranslatedKeyCount: number; + translatedKeys: number; /** Format: int64 */ - untranslatedWordCount: number; + reviewedKeys: number; /** Format: double */ untranslatedPercentage: number; - }; - ProjectStatsModel: { - /** Format: int64 */ - projectId: number; - /** Format: int32 */ - languageCount: number; - /** Format: int64 */ - keyCount: number; - /** Format: int64 */ - baseWordsCount: number; /** Format: double */ translatedPercentage: number; /** Format: double */ reviewedPercentage: number; /** Format: int64 */ - membersCount: number; + languageId: number; + disableActivityLogging: boolean; + }; + MtCreditBucket: { + userAccount?: components["schemas"]["UserAccount"]; + organization?: components["schemas"]["Organization"]; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; /** Format: int64 */ - tagCount: number; - languageStats: components["schemas"]["LanguageStatsModel"][]; + id: number; + /** Format: int64 */ + credits: number; + /** Format: int64 */ + extraCredits: number; + /** Format: int64 */ + bucketSize: number; + /** Format: date-time */ + refilled: string; + disableActivityLogging: boolean; }; - PagedModelLanguageModel: { - _embedded?: { - languages?: components["schemas"]["LanguageModel"][]; - }; - page?: components["schemas"]["PageMetadata"]; + MtServiceConfig: { + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + project: components["schemas"]["Project"]; + targetLanguage?: components["schemas"]["Language"]; + primaryService?: + | "GOOGLE" + | "AWS" + | "DEEPL" + | "AZURE" + | "BAIDU" + | "TOLGEE"; + primaryServiceFormality?: "FORMAL" | "INFORMAL" | "DEFAULT"; + enabledServices: ( + | "GOOGLE" + | "AWS" + | "DEEPL" + | "AZURE" + | "BAIDU" + | "TOLGEE" + )[]; + awsFormality: "FORMAL" | "INFORMAL" | "DEFAULT"; + deeplFormality: "FORMAL" | "INFORMAL" | "DEFAULT"; + tolgeeFormality: "FORMAL" | "INFORMAL" | "DEFAULT"; + primaryServiceInfo?: components["schemas"]["MtServiceInfo"]; + enabledServicesInfo: components["schemas"]["MtServiceInfo"][]; + disableActivityLogging: boolean; }; - CollectionModelLanguageAiPromptCustomizationModel: { - _embedded?: { - promptCustomizations?: components["schemas"]["LanguageAiPromptCustomizationModel"][]; - }; + Namespace: { + name: string; + project: components["schemas"]["Project"]; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + disableActivityLogging: boolean; }; - CollectionModelProjectInvitationModel: { - _embedded?: { - invitations?: components["schemas"]["ProjectInvitationModel"][]; - }; + NotificationPreferences: { + userAccount: components["schemas"]["UserAccount"]; + project?: components["schemas"]["Project"]; + disabledNotifications: ( + | "ACTIVITY_LANGUAGES_CREATED" + | "ACTIVITY_KEYS_CREATED" + | "ACTIVITY_KEYS_UPDATED" + | "ACTIVITY_KEYS_SCREENSHOTS_UPLOADED" + | "ACTIVITY_SOURCE_STRINGS_UPDATED" + | "ACTIVITY_TRANSLATIONS_UPDATED" + | "ACTIVITY_TRANSLATION_OUTDATED" + | "ACTIVITY_TRANSLATION_REVIEWED" + | "ACTIVITY_TRANSLATION_UNREVIEWED" + | "ACTIVITY_NEW_COMMENTS" + | "ACTIVITY_COMMENTS_MENTION" + | "BATCH_JOB_ERRORED" + )[]; + /** Format: int64 */ + id: number; }; - Pageable: { - /** Format: int32 */ - page?: number; - /** Format: int32 */ - size?: number; - sort?: string[]; + Organization: { + /** Format: int64 */ + id: number; + name: string; + description?: string; + slug: string; + mtCreditBucket?: components["schemas"]["MtCreditBucket"]; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + basePermission: components["schemas"]["Permission"]; + projects: components["schemas"]["Project"][]; + preferredBy: components["schemas"]["UserPreferences"][]; + avatarHash?: string; + /** Format: date-time */ + deletedAt?: string; + organizationSlackWorkspace: components["schemas"]["OrganizationSlackWorkspace"][]; }; - PagedModelApiKeyModel: { - _embedded?: { - apiKeys?: components["schemas"]["ApiKeyModel"][]; - }; - page?: components["schemas"]["PageMetadata"]; + OrganizationRole: { + invitation?: components["schemas"]["Invitation"]; + type: "MEMBER" | "OWNER"; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + user?: components["schemas"]["UserAccount"]; + organization: components["schemas"]["Organization"]; + disableActivityLogging: boolean; }; - PagedModelProjectWithStatsModel: { - _embedded?: { - projects?: components["schemas"]["ProjectWithStatsModel"][]; - }; - page?: components["schemas"]["PageMetadata"]; + OrganizationSlackWorkspace: { + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + organization: components["schemas"]["Organization"]; + author: components["schemas"]["UserAccount"]; + slackTeamId: string; + slackTeamName: string; + accessToken: string; + slackSubscriptions: components["schemas"]["SlackConfig"][]; + disableActivityLogging: boolean; + }; + Pat: { + tokenHash: string; + description: string; + /** Format: date-time */ + expiresAt?: string; + /** Format: date-time */ + lastUsedAt?: string; + token?: string; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + userAccount: components["schemas"]["UserAccount"]; + disableActivityLogging: boolean; + }; + Permission: { + /** Format: int64 */ + id: number; + user?: components["schemas"]["UserAccount"]; + organization?: components["schemas"]["Organization"]; + invitation?: components["schemas"]["Invitation"]; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + _scopes?: ( + | "translations.view" + | "translations.edit" + | "keys.edit" + | "screenshots.upload" + | "screenshots.delete" + | "screenshots.view" + | "activity.view" + | "languages.edit" + | "admin" + | "project.edit" + | "members.view" + | "members.edit" + | "translation-comments.add" + | "translation-comments.edit" + | "translation-comments.set-state" + | "translations.state-edit" + | "keys.view" + | "keys.delete" + | "keys.create" + | "batch-jobs.view" + | "batch-jobs.cancel" + | "translations.batch-by-tm" + | "translations.batch-machine" + | "content-delivery.manage" + | "content-delivery.publish" + | "webhooks.manage" + )[]; + type?: "NONE" | "VIEW" | "TRANSLATE" | "REVIEW" | "EDIT" | "MANAGE"; + translateLanguages: components["schemas"]["Language"][]; + viewLanguages: components["schemas"]["Language"][]; + stateChangeLanguages: components["schemas"]["Language"][]; + project?: components["schemas"]["Project"]; + translateLanguageIds?: number[]; + stateChangeLanguageIds?: number[]; + /** Format: int64 */ + userId?: number; + scopes: ( + | "translations.view" + | "translations.edit" + | "keys.edit" + | "screenshots.upload" + | "screenshots.delete" + | "screenshots.view" + | "activity.view" + | "languages.edit" + | "admin" + | "project.edit" + | "members.view" + | "members.edit" + | "translation-comments.add" + | "translation-comments.edit" + | "translation-comments.set-state" + | "translations.state-edit" + | "keys.view" + | "keys.delete" + | "keys.create" + | "batch-jobs.view" + | "batch-jobs.cancel" + | "translations.batch-by-tm" + | "translations.batch-machine" + | "content-delivery.manage" + | "content-delivery.publish" + | "webhooks.manage" + )[]; + granular: boolean; + /** Format: int64 */ + projectId?: number; + viewLanguageIds?: number[]; + /** Format: int64 */ + organizationId?: number; + /** Format: int64 */ + invitationId?: number; + }; + Project: { + /** Format: int64 */ + id: number; + name: string; + description?: string; + aiTranslatorPromptDescription?: string; + slug?: string; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + languages: components["schemas"]["Language"][]; + permissions: components["schemas"]["Permission"][]; + keys: components["schemas"]["Key"][]; + apiKeys: components["schemas"]["ApiKey"][]; + userOwner?: components["schemas"]["UserAccount"]; + organizationOwner: components["schemas"]["Organization"]; + baseLanguage?: components["schemas"]["Language"]; + autoTranslationConfigs: components["schemas"]["AutoTranslationConfig"][]; + mtServiceConfig: components["schemas"]["MtServiceConfig"][]; + namespaces: components["schemas"]["Namespace"][]; + defaultNamespace?: components["schemas"]["Namespace"]; + avatarHash?: string; + automations: components["schemas"]["Automation"][]; + contentDeliveryConfigs: components["schemas"]["ContentDeliveryConfig"][]; + contentStorages: components["schemas"]["ContentStorage"][]; + webhookConfigs: components["schemas"]["WebhookConfig"][]; + slackConfigs: components["schemas"]["SlackConfig"][]; + /** @description Whether to disable ICU placeholder visualization in the editor and it's support. */ + icuPlaceholders: boolean; + /** Format: date-time */ + deletedAt?: string; + disableActivityLogging: boolean; + }; + S3ContentStorageConfig: { + contentStorage: components["schemas"]["ContentStorage"]; + bucketName: string; + accessKey: string; + secretKey: string; + endpoint: string; + signingRegion: string; + enabled?: boolean; + contentStorageType?: "S3" | "AZURE"; + }; + SavedSlackMessage: { + messageTimestamp: string; + slackConfig: components["schemas"]["SlackConfig"]; + /** Format: int64 */ + keyId: number; + languageTags: string[]; + createdKeyBlocks: boolean; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + info: components["schemas"]["SlackMessageInfo"][]; + disableActivityLogging: boolean; }; - ProjectStatistics: { + Screenshot: { + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; /** Format: int64 */ - projectId: number; + id: number; + keyScreenshotReferences: components["schemas"]["KeyScreenshotReference"][]; + path: string; + extension?: string; + hasThumbnail: boolean; + location?: string; + /** Format: int32 */ + width: number; + /** Format: int32 */ + height: number; + hash: string; + filename: string; + thumbnailFilename: string; + pathWithSlash: string; + disableActivityLogging: boolean; + }; + SlackConfig: { + project: components["schemas"]["Project"]; + userAccount: components["schemas"]["UserAccount"]; + channelId: string; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; /** Format: int64 */ - keyCount: number; + id: number; + automationActions: components["schemas"]["AutomationAction"][]; + languageTags: string[]; + events: ("ALL" | "NEW_KEY" | "BASE_CHANGED" | "TRANSLATION_CHANGED")[]; + savedSlackMessage: components["schemas"]["SavedSlackMessage"][]; + isGlobalSubscription: boolean; + preferences: components["schemas"]["SlackConfigPreference"][]; + organizationSlackWorkspace?: components["schemas"]["OrganizationSlackWorkspace"]; + disableActivityLogging: boolean; + }; + SlackConfigPreference: { + slackConfig: components["schemas"]["SlackConfig"]; + languageTag?: string; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; /** Format: int64 */ - languageCount: number; - translationStatePercentages: { [key: string]: number }; + id: number; + events: ("ALL" | "NEW_KEY" | "BASE_CHANGED" | "TRANSLATION_CHANGED")[]; + disableActivityLogging: boolean; }; - ProjectWithStatsModel: { + SlackMessageInfo: { + slackMessage: components["schemas"]["SavedSlackMessage"]; + languageTag: string; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + subscriptionType: "GLOBAL"; + authorContext: string; + disableActivityLogging: boolean; + }; + SlackUserConnection: { + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + userAccount: components["schemas"]["UserAccount"]; + slackUserId: string; + slackTeamId: string; + disableActivityLogging: boolean; + }; + StorageConfig: { + enabled: boolean; + contentStorageType: "S3" | "AZURE"; + }; + Tag: { + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; /** Format: int64 */ id: number; name: string; - description?: string; - slug?: string; - avatar?: components["schemas"]["Avatar"]; - organizationOwner?: components["schemas"]["SimpleOrganizationModel"]; - baseLanguage?: components["schemas"]["LanguageModel"]; - organizationRole?: "MEMBER" | "OWNER"; - directPermission?: components["schemas"]["PermissionModel"]; - computedPermission: components["schemas"]["ComputedPermissionModel"]; - stats: components["schemas"]["ProjectStatistics"]; - languages: components["schemas"]["LanguageModel"][]; - /** @description Whether to disable ICU placeholder visualization in the editor and it's support. */ - icuPlaceholders: boolean; + project: components["schemas"]["Project"]; + keyMetas: components["schemas"]["KeyMeta"][]; + disableActivityLogging: boolean; }; - CollectionModelScreenshotModel: { - _embedded?: { - screenshots?: components["schemas"]["ScreenshotModel"][]; + Translation: { + text?: { + old?: string; + new?: string; }; - }; - PagedModelPatModel: { - _embedded?: { - pats?: components["schemas"]["PatModel"][]; + state?: { + old?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + new?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + }; + auto?: { + old?: boolean; + new?: boolean; + }; + mtProvider?: { + old?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE"; + new?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE"; + }; + outdated?: { + old?: boolean; + new?: boolean; }; - page?: components["schemas"]["PageMetadata"]; }; - PatWithUserModel: { - user: components["schemas"]["SimpleUserAccountModel"]; + UserAccount: { /** Format: int64 */ id: number; + username: string; + password?: string; + name: string; + role?: "USER" | "ADMIN"; + accountType?: "LOCAL" | "MANAGED" | "THIRD_PARTY"; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: byte */ + totpKey?: string; + mfaRecoveryCodes: string[]; + /** Format: date-time */ + tokensValidNotBefore?: string; + permissions: components["schemas"]["Permission"][]; + emailVerification?: components["schemas"]["EmailVerification"]; + thirdPartyAuthType?: string; + thirdPartyAuthId?: string; + resetPasswordCode?: string; + organizationRoles: components["schemas"]["OrganizationRole"][]; + preferences?: components["schemas"]["UserPreferences"]; + pats?: components["schemas"]["Pat"][]; + apiKeys?: components["schemas"]["ApiKey"][]; + avatarHash?: string; + /** Format: date-time */ + deletedAt?: string; + /** Format: date-time */ + disabledAt?: string; + isInitialUser: boolean; + passwordChanged: boolean; + isDemo: boolean; + slackUserConnection: components["schemas"]["SlackUserConnection"][]; + slackConfig: components["schemas"]["SlackConfig"][]; + userNotifications: components["schemas"]["UserNotification"][]; + projectNotificationPreferences: components["schemas"]["NotificationPreferences"][]; + globalNotificationPreferences?: components["schemas"]["NotificationPreferences"]; + deletable?: boolean; + deleted: boolean; + mfaEnabled?: boolean; + needsSuperJwt?: boolean; + }; + UserNotification: { + type: + | "ACTIVITY_LANGUAGES_CREATED" + | "ACTIVITY_KEYS_CREATED" + | "ACTIVITY_KEYS_UPDATED" + | "ACTIVITY_KEYS_SCREENSHOTS_UPLOADED" + | "ACTIVITY_SOURCE_STRINGS_UPDATED" + | "ACTIVITY_TRANSLATIONS_UPDATED" + | "ACTIVITY_TRANSLATION_OUTDATED" + | "ACTIVITY_TRANSLATION_REVIEWED" + | "ACTIVITY_TRANSLATION_UNREVIEWED" + | "ACTIVITY_NEW_COMMENTS" + | "ACTIVITY_COMMENTS_MENTION" + | "BATCH_JOB_ERRORED"; + recipient: components["schemas"]["UserAccount"]; + project?: components["schemas"]["Project"]; + modifiedEntities: components["schemas"]["ActivityModifiedEntity"][]; + batchJob?: components["schemas"]["BatchJob"]; /** Format: int64 */ - createdAt: number; - /** Format: int64 */ - updatedAt: number; - /** Format: int64 */ - lastUsedAt?: number; + id: number; + unread: boolean; + /** Format: date-time */ + markedDoneAt?: string; + /** Format: date-time */ + lastUpdated: string; + }; + UserPreferences: { + userAccount: components["schemas"]["UserAccount"]; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + language?: string; + preferredOrganization?: components["schemas"]["Organization"]; /** Format: int64 */ - expiresAt?: number; - description: string; + id: number; }; - PagedModelOrganizationModel: { - _embedded?: { - organizations?: components["schemas"]["OrganizationModel"][]; - }; - page?: components["schemas"]["PageMetadata"]; + WebhookConfig: { + project: components["schemas"]["Project"]; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: int64 */ + id: number; + url: string; + webhookSecret: string; + automationActions: components["schemas"]["AutomationAction"][]; + /** Format: date-time */ + firstFailed?: string; + /** Format: date-time */ + lastExecuted?: string; + disableActivityLogging: boolean; }; - CollectionModelOrganizationInvitationModel: { - _embedded?: { - organizationInvitations?: components["schemas"]["OrganizationInvitationModel"][]; + EntityDescription: { + entityClass: string; + /** Format: int64 */ + entityId: number; + data: { + name?: string; }; }; - PublicUsageModel: { + ProjectActivityUnknownModel: { /** Format: int64 */ - organizationId: number; - /** - * Format: int64 - * @description Current balance of standard credits. Standard credits are refilled every month - */ - creditBalance: number; - /** - * Format: int64 - * @description How many credits are included in your current plan - */ - includedMtCredits: number; - /** - * Format: int64 - * @description Date when credits were refilled. (In epoch format) - */ - creditBalanceRefilledAt: number; - /** - * Format: int64 - * @description Date when credits will be refilled. (In epoch format) - */ - creditBalanceNextRefillAt: number; - /** - * Format: int64 - * @description Currently used credits over credits included in plan and extra credits - */ - currentPayAsYouGoMtCredits: number; - /** - * Format: int64 - * @description The maximum amount organization can spend on MT credit usage before they reach the spending limit - */ - availablePayAsYouGoMtCredits: number; - /** - * Format: int64 - * @description Extra credits, which are neither refilled nor reset every month. These credits are used when there are no standard credits - */ - extraCreditBalance: number; - /** - * Format: int64 - * @description How many translations can be stored within your organization - */ - translationSlotsLimit: number; - /** - * Format: int64 - * @description How many translation slots are included in current subscription plan. How many translation slots can organization use without additional costs - */ - includedTranslationSlots: number; - /** - * Format: int64 - * @description How many translations are included in current subscription plan. How many translations can organization use without additional costs - */ - includedTranslations: number; - /** - * Format: int64 - * @description How many translations slots are currently used by organization - */ - currentTranslationSlots: number; - /** - * Format: int64 - * @description How many non-empty translations are currently stored by organization - */ - currentTranslations: number; - /** - * Format: int64 - * @description How many translations can be stored until reaching the limit. (For pay us you go, the top limit is the spending limit) - */ - translationsLimit: number; + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "UNKNOWN"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; }; - CollectionModelWorkspaceModel: { - _embedded?: { - workspaces?: components["schemas"]["WorkspaceModel"][]; + ProjectActivitySetTranslationStateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "SET_TRANSLATION_STATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + Translation?: { + entityClass?: string; + /** Format: int64 */ + entityId?: number; + description?: { [key: string]: { [key: string]: unknown } }; + modifications?: { + text?: { + old?: string; + new?: string; + }; + state?: { + old?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + new?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + }; + auto?: { + old?: boolean; + new?: boolean; + }; + mtProvider?: { + old?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE"; + new?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE"; + }; + outdated?: { + old?: boolean; + new?: boolean; + }; + }; + relations?: { + [key: string]: components["schemas"]["ExistenceEntityDescription"]; + }; + exists?: boolean; + }; }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; }; - WorkspaceModel: { + ProjectActivitySetTranslationsModel: { /** Format: int64 */ - id: number; - slackTeamName: string; - slackTeamId: string; - }; - ConnectToSlackUrlModel: { - url: string; - }; - PagedModelUserAccountWithOrganizationRoleModel: { - _embedded?: { - usersInOrganization?: components["schemas"]["UserAccountWithOrganizationRoleModel"][]; + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "SET_TRANSLATIONS"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + Translation?: { + entityClass?: string; + /** Format: int64 */ + entityId?: number; + description?: { [key: string]: { [key: string]: unknown } }; + modifications?: { + text?: { + old?: string; + new?: string; + }; + state?: { + old?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + new?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + }; + auto?: { + old?: boolean; + new?: boolean; + }; + mtProvider?: { + old?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE"; + new?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE"; + }; + outdated?: { + old?: boolean; + new?: boolean; + }; + }; + relations?: { + [key: string]: components["schemas"]["ExistenceEntityDescription"]; + }; + exists?: boolean; + }; }; - page?: components["schemas"]["PageMetadata"]; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; }; - SimpleProjectModel: { + ProjectActivityDismissAutoTranslatedStateModel: { /** Format: int64 */ - id: number; - name: string; - description?: string; - slug?: string; - avatar?: components["schemas"]["Avatar"]; - baseLanguage?: components["schemas"]["LanguageModel"]; - icuPlaceholders: boolean; + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "DISMISS_AUTO_TRANSLATED_STATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: { + Translation?: { + entityClass?: string; + /** Format: int64 */ + entityId?: number; + description?: { [key: string]: { [key: string]: unknown } }; + modifications?: { + text?: { + old?: string; + new?: string; + }; + state?: { + old?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + new?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + }; + auto?: { + old?: boolean; + new?: boolean; + }; + mtProvider?: { + old?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE"; + new?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE"; + }; + outdated?: { + old?: boolean; + new?: boolean; + }; + }; + relations?: { + [key: string]: components["schemas"]["ExistenceEntityDescription"]; + }; + exists?: boolean; + }; + }; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; }; - UserAccountWithOrganizationRoleModel: { + ProjectActivitySetOutdatedFlagModel: { /** Format: int64 */ - id: number; - name: string; - username: string; - organizationRole?: "MEMBER" | "OWNER"; - projectsWithDirectPermission: components["schemas"]["SimpleProjectModel"][]; - avatar?: components["schemas"]["Avatar"]; + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "SET_OUTDATED_FLAG"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; }; - SimpleModifiedEntityView: { - entityClass: string; + ProjectActivityTranslationCommentAddModel: { /** Format: int64 */ - entityId: number; - exists?: boolean; - modifications: { - [key: string]: components["schemas"]["PropertyModification"]; - }; - description?: { [key: string]: { [key: string]: unknown } }; - describingRelations?: { - [key: string]: components["schemas"]["ExistenceEntityDescription"]; - }; + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "TRANSLATION_COMMENT_ADD"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; }; - UserNotificationModel: { + ProjectActivityTranslationCommentDeleteModel: { /** Format: int64 */ - id: number; - type: - | "ACTIVITY_LANGUAGES_CREATED" - | "ACTIVITY_KEYS_CREATED" - | "ACTIVITY_KEYS_UPDATED" - | "ACTIVITY_KEYS_SCREENSHOTS_UPLOADED" - | "ACTIVITY_SOURCE_STRINGS_UPDATED" - | "ACTIVITY_TRANSLATIONS_UPDATED" - | "ACTIVITY_TRANSLATION_OUTDATED" - | "ACTIVITY_TRANSLATION_REVIEWED" - | "ACTIVITY_TRANSLATION_UNREVIEWED" - | "ACTIVITY_NEW_COMMENTS" - | "ACTIVITY_COMMENTS_MENTION" - | "BATCH_JOB_ERRORED"; - project?: components["schemas"]["SimpleProjectModel"]; - batchJob?: components["schemas"]["BatchJobModel"]; - modifiedEntities?: components["schemas"]["SimpleModifiedEntityView"][]; - unread: boolean; - /** Format: date-time */ - markedDoneAt?: string; - /** Format: date-time */ - lastUpdated: string; + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "TRANSLATION_COMMENT_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; }; - ApiKeyWithLanguagesModel: { - /** - * @deprecated - * @description Languages for which user has translate permission. - */ - permittedLanguageIds?: number[]; + ProjectActivityTranslationCommentEditModel: { /** Format: int64 */ - id: number; - scopes: string[]; + revisionId: number; /** Format: int64 */ - projectId: number; - username?: string; + timestamp: number; + type: "TRANSLATION_COMMENT_EDIT"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityTranslationCommentSetStateModel: { /** Format: int64 */ - lastUsedAt?: number; + revisionId: number; /** Format: int64 */ - expiresAt?: number; - description: string; - projectName: string; - userFullName?: string; + timestamp: number; + type: "TRANSLATION_COMMENT_SET_STATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; }; - PagedModelUserAccountModel: { - _embedded?: { - users?: components["schemas"]["UserAccountModel"][]; - }; - page?: components["schemas"]["PageMetadata"]; + ProjectActivityScreenshotDeleteModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "SCREENSHOT_DELETE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; }; - UserAccountModel: { + ProjectActivityScreenshotAddModel: { /** Format: int64 */ - id: number; - username: string; - name?: string; - emailAwaitingVerification?: string; - avatar?: components["schemas"]["Avatar"]; - globalServerRole: "USER" | "ADMIN"; - deleted: boolean; - disabled: boolean; + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "SCREENSHOT_ADD"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; }; - UserTotpDisableRequestDto: { - password: string; + ProjectActivityKeyTagsEditModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "KEY_TAGS_EDIT"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; }; - DeleteKeysDto: { - /** @description IDs of keys to delete */ - ids: number[]; + ProjectActivityKeyNameEditModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "KEY_NAME_EDIT"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; }; - ProjectActivityUnknownModel: { + ProjectActivityKeyDeleteModel: { /** Format: int64 */ revisionId: number; /** Format: int64 */ timestamp: number; - type: "UNKNOWN"; + type: "KEY_DELETE"; author?: components["schemas"]["ProjectActivityAuthorModel"]; modifiedEntities?: unknown; meta?: { [key: string]: { [key: string]: unknown } }; counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - ProjectActivitySetTranslationStateModel: { + ProjectActivityCreateKeyModel: { /** Format: int64 */ revisionId: number; /** Format: int64 */ timestamp: number; - type: "SET_TRANSLATION_STATE"; + type: "CREATE_KEY"; author?: components["schemas"]["ProjectActivityAuthorModel"]; modifiedEntities?: { - Translation?: { + Key?: { entityClass?: string; /** Format: int64 */ entityId?: number; description?: { [key: string]: { [key: string]: unknown } }; modifications?: { - text?: { - old?: string; + name?: { + old?: unknown; new?: string; }; - state?: { - old?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; - new?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; - }; - auto?: { - old?: boolean; + isPlural?: { + old?: unknown; new?: boolean; }; - mtProvider?: { - old?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE"; - new?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE"; + pluralArgName?: { + old?: unknown; + new?: string; }; - outdated?: { - old?: boolean; - new?: boolean; + namespace?: { + old?: unknown; + new?: { + entityClass: string; + /** Format: int64 */ + entityId: number; + data: { + name?: string; + }; + }; }; }; relations?: { @@ -5178,44 +7388,28 @@ export interface components { }; exists?: boolean; }; - }; - meta?: { [key: string]: { [key: string]: unknown } }; - counts?: { [key: string]: number }; - params?: { [key: string]: unknown }; - }; - ProjectActivitySetTranslationsModel: { - /** Format: int64 */ - revisionId: number; - /** Format: int64 */ - timestamp: number; - type: "SET_TRANSLATIONS"; - author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: { - Translation?: { + KeyMeta?: { entityClass?: string; /** Format: int64 */ entityId?: number; description?: { [key: string]: { [key: string]: unknown } }; modifications?: { - text?: { - old?: string; + description?: { + old?: unknown; new?: string; }; - state?: { - old?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; - new?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; - }; - auto?: { - old?: boolean; - new?: boolean; - }; - mtProvider?: { - old?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE"; - new?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE"; + custom?: { + old?: unknown; + new?: { [key: string]: { [key: string]: unknown } }; }; - outdated?: { - old?: boolean; - new?: boolean; + tags?: { + old?: unknown; + new?: { + entityClass: string; + /** Format: int64 */ + entityId: number; + data: { [key: string]: unknown }; + }; }; }; relations?: { @@ -5228,595 +7422,716 @@ export interface components { counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - ProjectActivityDismissAutoTranslatedStateModel: { + ProjectActivityComplexEditModel: { /** Format: int64 */ revisionId: number; /** Format: int64 */ timestamp: number; - type: "DISMISS_AUTO_TRANSLATED_STATE"; + type: "COMPLEX_EDIT"; author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: { - Translation?: { - entityClass?: string; - /** Format: int64 */ - entityId?: number; - description?: { [key: string]: { [key: string]: unknown } }; - modifications?: { - text?: { - old?: string; - new?: string; - }; - state?: { - old?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; - new?: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; - }; - auto?: { - old?: boolean; - new?: boolean; - }; - mtProvider?: { - old?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE"; - new?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE"; - }; - outdated?: { - old?: boolean; - new?: boolean; - }; - }; - relations?: { - [key: string]: components["schemas"]["ExistenceEntityDescription"]; - }; - exists?: boolean; - }; - }; + modifiedEntities?: unknown; meta?: { [key: string]: { [key: string]: unknown } }; counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - ProjectActivitySetOutdatedFlagModel: { + ProjectActivityImportModel: { /** Format: int64 */ revisionId: number; /** Format: int64 */ timestamp: number; - type: "SET_OUTDATED_FLAG"; + type: "IMPORT"; author?: components["schemas"]["ProjectActivityAuthorModel"]; modifiedEntities?: unknown; meta?: { [key: string]: { [key: string]: unknown } }; counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - ProjectActivityTranslationCommentAddModel: { + ProjectActivityCreateLanguageModel: { /** Format: int64 */ revisionId: number; /** Format: int64 */ timestamp: number; - type: "TRANSLATION_COMMENT_ADD"; + type: "CREATE_LANGUAGE"; author?: components["schemas"]["ProjectActivityAuthorModel"]; modifiedEntities?: unknown; meta?: { [key: string]: { [key: string]: unknown } }; counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - ProjectActivityTranslationCommentDeleteModel: { + ProjectActivityEditLanguageModel: { /** Format: int64 */ revisionId: number; /** Format: int64 */ timestamp: number; - type: "TRANSLATION_COMMENT_DELETE"; + type: "EDIT_LANGUAGE"; author?: components["schemas"]["ProjectActivityAuthorModel"]; modifiedEntities?: unknown; meta?: { [key: string]: { [key: string]: unknown } }; counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - ProjectActivityTranslationCommentEditModel: { + ProjectActivityDeleteLanguageModel: { /** Format: int64 */ revisionId: number; /** Format: int64 */ timestamp: number; - type: "TRANSLATION_COMMENT_EDIT"; + type: "DELETE_LANGUAGE"; author?: components["schemas"]["ProjectActivityAuthorModel"]; modifiedEntities?: unknown; meta?: { [key: string]: { [key: string]: unknown } }; counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - ProjectActivityTranslationCommentSetStateModel: { + ProjectActivityHardDeleteLanguageModel: { /** Format: int64 */ revisionId: number; /** Format: int64 */ timestamp: number; - type: "TRANSLATION_COMMENT_SET_STATE"; + type: "HARD_DELETE_LANGUAGE"; author?: components["schemas"]["ProjectActivityAuthorModel"]; modifiedEntities?: unknown; meta?: { [key: string]: { [key: string]: unknown } }; counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - ProjectActivityScreenshotDeleteModel: { + ProjectActivityCreateProjectModel: { /** Format: int64 */ revisionId: number; /** Format: int64 */ timestamp: number; - type: "SCREENSHOT_DELETE"; + type: "CREATE_PROJECT"; author?: components["schemas"]["ProjectActivityAuthorModel"]; modifiedEntities?: unknown; meta?: { [key: string]: { [key: string]: unknown } }; counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - ProjectActivityScreenshotAddModel: { + ProjectActivityEditProjectModel: { /** Format: int64 */ revisionId: number; /** Format: int64 */ timestamp: number; - type: "SCREENSHOT_ADD"; + type: "EDIT_PROJECT"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityNamespaceEditModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "NAMESPACE_EDIT"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityBatchPreTranslateByTmModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_PRE_TRANSLATE_BY_TM"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityBatchMachineTranslateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_MACHINE_TRANSLATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityAutoTranslateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "AUTO_TRANSLATE"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityBatchClearTranslationsModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_CLEAR_TRANSLATIONS"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityBatchCopyTranslationsModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_COPY_TRANSLATIONS"; + author?: components["schemas"]["ProjectActivityAuthorModel"]; + modifiedEntities?: unknown; + meta?: { [key: string]: { [key: string]: unknown } }; + counts?: { [key: string]: number }; + params?: { [key: string]: unknown }; + }; + ProjectActivityBatchSetTranslationStateModel: { + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + type: "BATCH_SET_TRANSLATION_STATE"; author?: components["schemas"]["ProjectActivityAuthorModel"]; modifiedEntities?: unknown; meta?: { [key: string]: { [key: string]: unknown } }; counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - ProjectActivityKeyTagsEditModel: { + ProjectActivityBatchTagKeysModel: { /** Format: int64 */ revisionId: number; /** Format: int64 */ timestamp: number; - type: "KEY_TAGS_EDIT"; + type: "BATCH_TAG_KEYS"; author?: components["schemas"]["ProjectActivityAuthorModel"]; modifiedEntities?: unknown; meta?: { [key: string]: { [key: string]: unknown } }; counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - ProjectActivityKeyNameEditModel: { + ProjectActivityBatchUntagKeysModel: { /** Format: int64 */ revisionId: number; /** Format: int64 */ timestamp: number; - type: "KEY_NAME_EDIT"; + type: "BATCH_UNTAG_KEYS"; author?: components["schemas"]["ProjectActivityAuthorModel"]; modifiedEntities?: unknown; meta?: { [key: string]: { [key: string]: unknown } }; counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - ProjectActivityKeyDeleteModel: { + ProjectActivityBatchSetKeysNamespaceModel: { /** Format: int64 */ revisionId: number; /** Format: int64 */ timestamp: number; - type: "KEY_DELETE"; + type: "BATCH_SET_KEYS_NAMESPACE"; author?: components["schemas"]["ProjectActivityAuthorModel"]; modifiedEntities?: unknown; meta?: { [key: string]: { [key: string]: unknown } }; counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - ProjectActivityCreateKeyModel: { + ProjectActivityAutomationModel: { /** Format: int64 */ revisionId: number; /** Format: int64 */ timestamp: number; - type: "CREATE_KEY"; + type: "AUTOMATION"; author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: { - Key?: { - entityClass?: string; - /** Format: int64 */ - entityId?: number; - description?: { [key: string]: { [key: string]: unknown } }; - modifications?: { - name?: { - old?: unknown; - new?: string; - }; - isPlural?: { - old?: unknown; - new?: boolean; - }; - pluralArgName?: { - old?: unknown; - new?: string; - }; - namespace?: { - old?: unknown; - new?: { - entityClass: string; - /** Format: int64 */ - entityId: number; - data: { - name?: string; - }; - }; - }; - }; - relations?: { - [key: string]: components["schemas"]["ExistenceEntityDescription"]; - }; - exists?: boolean; - }; - KeyMeta?: { - entityClass?: string; - /** Format: int64 */ - entityId?: number; - description?: { [key: string]: { [key: string]: unknown } }; - modifications?: { - description?: { - old?: unknown; - new?: string; - }; - custom?: { - old?: unknown; - new?: { [key: string]: { [key: string]: unknown } }; - }; - tags?: { - old?: unknown; - new?: { - entityClass: string; - /** Format: int64 */ - entityId: number; - data: { [key: string]: unknown }; - }; - }; - }; - relations?: { - [key: string]: components["schemas"]["ExistenceEntityDescription"]; - }; - exists?: boolean; - }; - }; + modifiedEntities?: unknown; meta?: { [key: string]: { [key: string]: unknown } }; counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - ProjectActivityComplexEditModel: { + ProjectActivityContentDeliveryConfigCreateModel: { /** Format: int64 */ revisionId: number; /** Format: int64 */ timestamp: number; - type: "COMPLEX_EDIT"; + type: "CONTENT_DELIVERY_CONFIG_CREATE"; author?: components["schemas"]["ProjectActivityAuthorModel"]; modifiedEntities?: unknown; meta?: { [key: string]: { [key: string]: unknown } }; counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - ProjectActivityImportModel: { + ProjectActivityContentDeliveryConfigUpdateModel: { /** Format: int64 */ revisionId: number; /** Format: int64 */ timestamp: number; - type: "IMPORT"; + type: "CONTENT_DELIVERY_CONFIG_UPDATE"; author?: components["schemas"]["ProjectActivityAuthorModel"]; modifiedEntities?: unknown; meta?: { [key: string]: { [key: string]: unknown } }; counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - ProjectActivityCreateLanguageModel: { + ProjectActivityContentDeliveryConfigDeleteModel: { /** Format: int64 */ revisionId: number; /** Format: int64 */ timestamp: number; - type: "CREATE_LANGUAGE"; + type: "CONTENT_DELIVERY_CONFIG_DELETE"; author?: components["schemas"]["ProjectActivityAuthorModel"]; modifiedEntities?: unknown; meta?: { [key: string]: { [key: string]: unknown } }; counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - ProjectActivityEditLanguageModel: { + ProjectActivityContentStorageCreateModel: { /** Format: int64 */ revisionId: number; /** Format: int64 */ timestamp: number; - type: "EDIT_LANGUAGE"; + type: "CONTENT_STORAGE_CREATE"; author?: components["schemas"]["ProjectActivityAuthorModel"]; modifiedEntities?: unknown; meta?: { [key: string]: { [key: string]: unknown } }; counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - ProjectActivityDeleteLanguageModel: { + ProjectActivityContentStorageUpdateModel: { /** Format: int64 */ revisionId: number; /** Format: int64 */ timestamp: number; - type: "DELETE_LANGUAGE"; + type: "CONTENT_STORAGE_UPDATE"; author?: components["schemas"]["ProjectActivityAuthorModel"]; modifiedEntities?: unknown; meta?: { [key: string]: { [key: string]: unknown } }; counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - ProjectActivityHardDeleteLanguageModel: { + ProjectActivityContentStorageDeleteModel: { /** Format: int64 */ revisionId: number; /** Format: int64 */ timestamp: number; - type: "HARD_DELETE_LANGUAGE"; + type: "CONTENT_STORAGE_DELETE"; author?: components["schemas"]["ProjectActivityAuthorModel"]; modifiedEntities?: unknown; meta?: { [key: string]: { [key: string]: unknown } }; counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - ProjectActivityCreateProjectModel: { + ProjectActivityWebhookConfigCreateModel: { /** Format: int64 */ revisionId: number; /** Format: int64 */ timestamp: number; - type: "CREATE_PROJECT"; + type: "WEBHOOK_CONFIG_CREATE"; author?: components["schemas"]["ProjectActivityAuthorModel"]; modifiedEntities?: unknown; meta?: { [key: string]: { [key: string]: unknown } }; counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - ProjectActivityEditProjectModel: { + ProjectActivityWebhookConfigUpdateModel: { /** Format: int64 */ revisionId: number; /** Format: int64 */ timestamp: number; - type: "EDIT_PROJECT"; + type: "WEBHOOK_CONFIG_UPDATE"; author?: components["schemas"]["ProjectActivityAuthorModel"]; modifiedEntities?: unknown; meta?: { [key: string]: { [key: string]: unknown } }; counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - ProjectActivityNamespaceEditModel: { + ProjectActivityWebhookConfigDeleteModel: { /** Format: int64 */ revisionId: number; /** Format: int64 */ timestamp: number; - type: "NAMESPACE_EDIT"; + type: "WEBHOOK_CONFIG_DELETE"; author?: components["schemas"]["ProjectActivityAuthorModel"]; modifiedEntities?: unknown; meta?: { [key: string]: { [key: string]: unknown } }; counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - ProjectActivityBatchPreTranslateByTmModel: { + ProjectActivityComplexTagOperationModel: { /** Format: int64 */ revisionId: number; /** Format: int64 */ timestamp: number; - type: "BATCH_PRE_TRANSLATE_BY_TM"; + type: "COMPLEX_TAG_OPERATION"; author?: components["schemas"]["ProjectActivityAuthorModel"]; modifiedEntities?: unknown; meta?: { [key: string]: { [key: string]: unknown } }; counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; - ProjectActivityBatchMachineTranslateModel: { + CreateKeyGroupModel: { + /** Format: int32 */ + keyCount: number; + }; + ActivityGroupLanguageModel: { + /** Format: int64 */ + id: number; + name: string; + originalName: string; + tag: string; + flagEmoji: string; + }; + CreateProjectGroupModel: { + /** Format: int64 */ + id: number; + name: string; + languages: components["schemas"]["ActivityGroupLanguageModel"][]; + description?: string; + }; + ActivityGroupSetTranslationStateModel: { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "SET_TRANSLATION_STATE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + }; + ActivityGroupReviewModel: { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "REVIEW"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + }; + ActivityGroupSetTranslationsModel: { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "SET_TRANSLATIONS"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + }; + ActivityGroupDismissAutoTranslatedStateModel: { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "DISMISS_AUTO_TRANSLATED_STATE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + }; + ActivityGroupSetOutdatedFlagModel: { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "SET_OUTDATED_FLAG"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + }; + ActivityGroupAddTranslationCommentModel: { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "ADD_TRANSLATION_COMMENT"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + }; + ActivityGroupDeleteTranslationCommentModel: { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "DELETE_TRANSLATION_COMMENT"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + }; + ActivityGroupEditTranslationCommentModel: { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "EDIT_TRANSLATION_COMMENT"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + }; + ActivityGroupSetTranslationCommentStateModel: { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "SET_TRANSLATION_COMMENT_STATE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + }; + ActivityGroupDeleteScreenshotModel: { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "DELETE_SCREENSHOT"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + }; + ActivityGroupAddScreenshotModel: { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "ADD_SCREENSHOT"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + }; + ActivityGroupEditKeyTagsModel: { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "EDIT_KEY_TAGS"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + }; + ActivityGroupEditKeyNameModel: { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "EDIT_KEY_NAME"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + }; + ActivityGroupDeleteKeyModel: { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "DELETE_KEY"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + }; + ActivityGroupCreateKeyModel: { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "CREATE_KEY"; + author?: components["schemas"]["SimpleUserAccountModel"]; + data?: { + /** Format: int32 */ + keyCount: number; + }; + mentionedLanguageIds: number[]; + }; + ActivityGroupImportModel: { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "IMPORT"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + }; + ActivityGroupCreateLanguageModel: { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "CREATE_LANGUAGE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + }; + ActivityGroupEditLanguageModel: { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "EDIT_LANGUAGE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + }; + ActivityGroupDeleteLanguageModel: { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "DELETE_LANGUAGE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + }; + ActivityGroupCreateProjectModel: { /** Format: int64 */ - revisionId: number; + id: number; /** Format: int64 */ timestamp: number; - type: "BATCH_MACHINE_TRANSLATE"; - author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: unknown; - meta?: { [key: string]: { [key: string]: unknown } }; - counts?: { [key: string]: number }; - params?: { [key: string]: unknown }; + type: "CREATE_PROJECT"; + author?: components["schemas"]["SimpleUserAccountModel"]; + data?: { + /** Format: int64 */ + id: number; + name: string; + languages: components["schemas"]["ActivityGroupLanguageModel"][]; + description?: string; + }; + mentionedLanguageIds: number[]; }; - ProjectActivityAutoTranslateModel: { + ActivityGroupEditProjectModel: { /** Format: int64 */ - revisionId: number; + id: number; /** Format: int64 */ timestamp: number; - type: "AUTO_TRANSLATE"; - author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: unknown; - meta?: { [key: string]: { [key: string]: unknown } }; - counts?: { [key: string]: number }; - params?: { [key: string]: unknown }; + type: "EDIT_PROJECT"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; }; - ProjectActivityBatchClearTranslationsModel: { + ActivityGroupNamespaceEditModel: { /** Format: int64 */ - revisionId: number; + id: number; /** Format: int64 */ timestamp: number; - type: "BATCH_CLEAR_TRANSLATIONS"; - author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: unknown; - meta?: { [key: string]: { [key: string]: unknown } }; - counts?: { [key: string]: number }; - params?: { [key: string]: unknown }; + type: "NAMESPACE_EDIT"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; }; - ProjectActivityBatchCopyTranslationsModel: { + ActivityGroupBatchPreTranslateByTmModel: { /** Format: int64 */ - revisionId: number; + id: number; /** Format: int64 */ timestamp: number; - type: "BATCH_COPY_TRANSLATIONS"; - author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: unknown; - meta?: { [key: string]: { [key: string]: unknown } }; - counts?: { [key: string]: number }; - params?: { [key: string]: unknown }; + type: "BATCH_PRE_TRANSLATE_BY_TM"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; }; - ProjectActivityBatchSetTranslationStateModel: { + ActivityGroupBatchMachineTranslateModel: { /** Format: int64 */ - revisionId: number; + id: number; /** Format: int64 */ timestamp: number; - type: "BATCH_SET_TRANSLATION_STATE"; - author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: unknown; - meta?: { [key: string]: { [key: string]: unknown } }; - counts?: { [key: string]: number }; - params?: { [key: string]: unknown }; + type: "BATCH_MACHINE_TRANSLATE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; }; - ProjectActivityBatchTagKeysModel: { + ActivityGroupAutoTranslateModel: { /** Format: int64 */ - revisionId: number; + id: number; /** Format: int64 */ timestamp: number; - type: "BATCH_TAG_KEYS"; - author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: unknown; - meta?: { [key: string]: { [key: string]: unknown } }; - counts?: { [key: string]: number }; - params?: { [key: string]: unknown }; + type: "AUTO_TRANSLATE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; }; - ProjectActivityBatchUntagKeysModel: { + ActivityGroupBatchClearTranslationsModel: { /** Format: int64 */ - revisionId: number; + id: number; /** Format: int64 */ timestamp: number; - type: "BATCH_UNTAG_KEYS"; - author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: unknown; - meta?: { [key: string]: { [key: string]: unknown } }; - counts?: { [key: string]: number }; - params?: { [key: string]: unknown }; + type: "BATCH_CLEAR_TRANSLATIONS"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; }; - ProjectActivityBatchSetKeysNamespaceModel: { + ActivityGroupBatchCopyTranslationsModel: { /** Format: int64 */ - revisionId: number; + id: number; /** Format: int64 */ timestamp: number; - type: "BATCH_SET_KEYS_NAMESPACE"; - author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: unknown; - meta?: { [key: string]: { [key: string]: unknown } }; - counts?: { [key: string]: number }; - params?: { [key: string]: unknown }; + type: "BATCH_COPY_TRANSLATIONS"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; }; - ProjectActivityAutomationModel: { + ActivityGroupBatchSetTranslationStateModel: { /** Format: int64 */ - revisionId: number; + id: number; /** Format: int64 */ timestamp: number; - type: "AUTOMATION"; - author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: unknown; - meta?: { [key: string]: { [key: string]: unknown } }; - counts?: { [key: string]: number }; - params?: { [key: string]: unknown }; + type: "BATCH_SET_TRANSLATION_STATE"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; }; - ProjectActivityContentDeliveryConfigCreateModel: { + ActivityGroupContentDeliveryConfigCreateModel: { /** Format: int64 */ - revisionId: number; + id: number; /** Format: int64 */ timestamp: number; type: "CONTENT_DELIVERY_CONFIG_CREATE"; - author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: unknown; - meta?: { [key: string]: { [key: string]: unknown } }; - counts?: { [key: string]: number }; - params?: { [key: string]: unknown }; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; }; - ProjectActivityContentDeliveryConfigUpdateModel: { + ActivityGroupContentDeliveryConfigUpdateModel: { /** Format: int64 */ - revisionId: number; + id: number; /** Format: int64 */ timestamp: number; type: "CONTENT_DELIVERY_CONFIG_UPDATE"; - author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: unknown; - meta?: { [key: string]: { [key: string]: unknown } }; - counts?: { [key: string]: number }; - params?: { [key: string]: unknown }; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; }; - ProjectActivityContentDeliveryConfigDeleteModel: { + ActivityGroupContentDeliveryConfigDeleteModel: { /** Format: int64 */ - revisionId: number; + id: number; /** Format: int64 */ timestamp: number; type: "CONTENT_DELIVERY_CONFIG_DELETE"; - author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: unknown; - meta?: { [key: string]: { [key: string]: unknown } }; - counts?: { [key: string]: number }; - params?: { [key: string]: unknown }; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; }; - ProjectActivityContentStorageCreateModel: { + ActivityGroupContentStorageCreateModel: { /** Format: int64 */ - revisionId: number; + id: number; /** Format: int64 */ timestamp: number; type: "CONTENT_STORAGE_CREATE"; - author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: unknown; - meta?: { [key: string]: { [key: string]: unknown } }; - counts?: { [key: string]: number }; - params?: { [key: string]: unknown }; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; }; - ProjectActivityContentStorageUpdateModel: { + ActivityGroupContentStorageUpdateModel: { /** Format: int64 */ - revisionId: number; + id: number; /** Format: int64 */ timestamp: number; type: "CONTENT_STORAGE_UPDATE"; - author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: unknown; - meta?: { [key: string]: { [key: string]: unknown } }; - counts?: { [key: string]: number }; - params?: { [key: string]: unknown }; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; }; - ProjectActivityContentStorageDeleteModel: { + ActivityGroupContentStorageDeleteModel: { /** Format: int64 */ - revisionId: number; + id: number; /** Format: int64 */ timestamp: number; type: "CONTENT_STORAGE_DELETE"; - author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: unknown; - meta?: { [key: string]: { [key: string]: unknown } }; - counts?: { [key: string]: number }; - params?: { [key: string]: unknown }; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; }; - ProjectActivityWebhookConfigCreateModel: { + ActivityGroupWebhookConfigCreateModel: { /** Format: int64 */ - revisionId: number; + id: number; /** Format: int64 */ timestamp: number; type: "WEBHOOK_CONFIG_CREATE"; - author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: unknown; - meta?: { [key: string]: { [key: string]: unknown } }; - counts?: { [key: string]: number }; - params?: { [key: string]: unknown }; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; }; - ProjectActivityWebhookConfigUpdateModel: { + ActivityGroupWebhookConfigUpdateModel: { /** Format: int64 */ - revisionId: number; + id: number; /** Format: int64 */ timestamp: number; type: "WEBHOOK_CONFIG_UPDATE"; - author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: unknown; - meta?: { [key: string]: { [key: string]: unknown } }; - counts?: { [key: string]: number }; - params?: { [key: string]: unknown }; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; }; - ProjectActivityWebhookConfigDeleteModel: { + ActivityGroupWebhookConfigDeleteModel: { /** Format: int64 */ - revisionId: number; + id: number; /** Format: int64 */ timestamp: number; type: "WEBHOOK_CONFIG_DELETE"; - author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: unknown; - meta?: { [key: string]: { [key: string]: unknown } }; - counts?: { [key: string]: number }; - params?: { [key: string]: unknown }; - }; - ProjectActivityComplexTagOperationModel: { - /** Format: int64 */ - revisionId: number; - /** Format: int64 */ - timestamp: number; - type: "COMPLEX_TAG_OPERATION"; - author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: unknown; - meta?: { [key: string]: { [key: string]: unknown } }; - counts?: { [key: string]: number }; - params?: { [key: string]: unknown }; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; }; }; } @@ -16307,6 +18622,46 @@ export interface operations { size?: number; /** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ sort?: string[]; + filterType?: + | "SET_TRANSLATION_STATE" + | "REVIEW" + | "SET_TRANSLATIONS" + | "DISMISS_AUTO_TRANSLATED_STATE" + | "SET_OUTDATED_FLAG" + | "ADD_TRANSLATION_COMMENT" + | "DELETE_TRANSLATION_COMMENT" + | "EDIT_TRANSLATION_COMMENT" + | "SET_TRANSLATION_COMMENT_STATE" + | "DELETE_SCREENSHOT" + | "ADD_SCREENSHOT" + | "EDIT_KEY_TAGS" + | "EDIT_KEY_NAME" + | "DELETE_KEY" + | "CREATE_KEY" + | "IMPORT" + | "CREATE_LANGUAGE" + | "EDIT_LANGUAGE" + | "DELETE_LANGUAGE" + | "CREATE_PROJECT" + | "EDIT_PROJECT" + | "NAMESPACE_EDIT" + | "BATCH_PRE_TRANSLATE_BY_TM" + | "BATCH_MACHINE_TRANSLATE" + | "AUTO_TRANSLATE" + | "BATCH_CLEAR_TRANSLATIONS" + | "BATCH_COPY_TRANSLATIONS" + | "BATCH_SET_TRANSLATION_STATE" + | "CONTENT_DELIVERY_CONFIG_CREATE" + | "CONTENT_DELIVERY_CONFIG_UPDATE" + | "CONTENT_DELIVERY_CONFIG_DELETE" + | "CONTENT_STORAGE_CREATE" + | "CONTENT_STORAGE_UPDATE" + | "CONTENT_STORAGE_DELETE" + | "WEBHOOK_CONFIG_CREATE" + | "WEBHOOK_CONFIG_UPDATE" + | "WEBHOOK_CONFIG_DELETE"; + filterLanguageIdIn?: number[]; + filterAuthorUserIdIn?: number[]; }; path: { projectId: number; @@ -16316,7 +18671,63 @@ export interface operations { /** OK */ 200: { content: { - "application/hal+json": components["schemas"]["PagedModelProjectActivityModel"]; + "application/hal+json": components["schemas"]["PagedModelActivityGroupModel"]; + }; + }; + /** Bad Request */ + 400: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Unauthorized */ + 401: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Forbidden */ + 403: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** Not Found */ + 404: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + getCreateKeyItems: { + parameters: { + query: { + /** Zero-based page index (0..N) */ + page?: number; + /** The size of the page to be returned */ + size?: number; + /** Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + }; + path: { + groupId: number; + projectId: number; + }; + }; + responses: { + /** OK */ + 200: { + content: { + "application/hal+json": components["schemas"]["PagedModelCreateKeyGroupItemModel"]; }; }; /** Bad Request */ diff --git a/webapp/src/views/projects/ActivityView.tsx b/webapp/src/views/projects/ActivityView.tsx new file mode 100644 index 0000000000..a023c6dd0a --- /dev/null +++ b/webapp/src/views/projects/ActivityView.tsx @@ -0,0 +1,31 @@ +import { useTranslate } from '@tolgee/react'; +import { BaseProjectView } from './BaseProjectView'; +import { useApiQuery } from 'tg.service/http/useQueryApi'; +import { useProject } from 'tg.hooks/useProject'; +import { PaginatedHateoasList } from 'tg.component/common/list/PaginatedHateoasList'; +import { ActivityGroupItem } from 'tg.component/activity/groups/ActivityGroupItem'; +import { ProjectLanguagesProvider } from 'tg.hooks/ProjectLanguagesProvider'; + +export const ActivityView = () => { + const { t } = useTranslate(); + + const project = useProject(); + + const groupsLoadable = useApiQuery({ + url: '/v2/projects/{projectId}/activity/groups', + method: 'get', + path: { projectId: project.id }, + query: {}, + }); + + return ( + + + } + /> + + + ); +}; diff --git a/webapp/src/views/projects/ProjectRouter.tsx b/webapp/src/views/projects/ProjectRouter.tsx index 9b39a5ba72..e47637e2bc 100644 --- a/webapp/src/views/projects/ProjectRouter.tsx +++ b/webapp/src/views/projects/ProjectRouter.tsx @@ -19,6 +19,7 @@ import { WebsocketPreview } from './WebsocketPreview'; import { DeveloperView } from './developer/DeveloperView'; import { HideObserver } from 'tg.component/layout/TopBar/HideObserver'; import { ActivityDetailRedirect } from 'tg.component/security/ActivityDetailRedirect'; +import { ActivityView } from './ActivityView'; const IntegrateView = React.lazy(() => import('tg.views/projects/integrate/IntegrateView').then((r) => ({ @@ -85,6 +86,9 @@ export const ProjectRouter = () => { + + + {/* Preview section... */} From 0431b7a4ba8a091ddf54db4d93c1d7abaeeb334b Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Thu, 22 Aug 2024 17:41:47 +0200 Subject: [PATCH 41/44] feat: "Create Key" group with items --- .../userAccount/SimpleUserAccountModelAssembler.kt | 1 - .../kotlin/io/tolgee/activity/ActivityService.kt | 2 +- .../activity/iterceptor/InterceptedEventsManager.kt | 13 +++++++------ .../testDataBuilder/builders/UserAccountBuilder.kt | 2 +- .../src/main/kotlin/io/tolgee/model/UserAccount.kt | 4 ++-- .../listeners/ActivityEventListener.kt | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/backend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/SimpleUserAccountModelAssembler.kt b/backend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/SimpleUserAccountModelAssembler.kt index 2654f2113e..89390c0255 100644 --- a/backend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/SimpleUserAccountModelAssembler.kt +++ b/backend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/SimpleUserAccountModelAssembler.kt @@ -3,7 +3,6 @@ package io.tolgee.hateoas.userAccount import io.tolgee.api.SimpleUserAccount import io.tolgee.api.v2.controllers.V2UserController import io.tolgee.dtos.cacheable.UserAccountDto -import io.tolgee.model.UserAccount import io.tolgee.service.AvatarService import org.springframework.hateoas.server.mvc.RepresentationModelAssemblerSupport import org.springframework.stereotype.Component diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/ActivityService.kt b/backend/data/src/main/kotlin/io/tolgee/activity/ActivityService.kt index a78d0195be..6fb8d261c0 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/ActivityService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/ActivityService.kt @@ -124,7 +124,7 @@ class ActivityService( @Transactional fun getProjectActivity( projectId: Long, - revisionId: Long + revisionId: Long, ): ProjectActivityView? { return ProjectActivityViewByRevisionProvider( applicationContext = applicationContext, diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/iterceptor/InterceptedEventsManager.kt b/backend/data/src/main/kotlin/io/tolgee/activity/iterceptor/InterceptedEventsManager.kt index a12293756e..af9641caa5 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/iterceptor/InterceptedEventsManager.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/iterceptor/InterceptedEventsManager.kt @@ -117,11 +117,12 @@ class InterceptedEventsManager( val changesMap = getChangesMap(entity, currentState, previousState, propertyNames) - activityModifiedEntity.revisionType = when { - // when we are replacing ADD with MOD, we want to keep ADD - activityModifiedEntity.revisionType == RevisionType.ADD && revisionType == RevisionType.MOD -> RevisionType.ADD - else -> revisionType - } + activityModifiedEntity.revisionType = + when { + // when we are replacing ADD with MOD, we want to keep ADD + activityModifiedEntity.revisionType == RevisionType.ADD && revisionType == RevisionType.MOD -> RevisionType.ADD + else -> revisionType + } activityModifiedEntity.modifications.putAll(changesMap) activityModifiedEntity.setEntityDescription(entity) @@ -157,7 +158,7 @@ class InterceptedEventsManager( activityHolder.modifiedEntities .computeIfAbsent(entity::class) { IdentityHashMap() } .computeIfAbsent( - entity + entity, ) { ActivityModifiedEntity( activityRevision, diff --git a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/UserAccountBuilder.kt b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/UserAccountBuilder.kt index 4f40c6e470..9abe90c3d7 100644 --- a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/UserAccountBuilder.kt +++ b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/UserAccountBuilder.kt @@ -5,8 +5,8 @@ import io.tolgee.development.testDataBuilder.builders.slack.SlackUserConnectionB import io.tolgee.model.Pat import io.tolgee.model.UserAccount import io.tolgee.model.UserPreferences -import io.tolgee.model.slackIntegration.SlackUserConnection import io.tolgee.model.notifications.NotificationPreferences +import io.tolgee.model.slackIntegration.SlackUserConnection import org.springframework.core.io.ClassPathResource class UserAccountBuilder( diff --git a/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt b/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt index 92076c712d..10c37bc1a6 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt @@ -3,10 +3,10 @@ package io.tolgee.model import io.hypersistence.utils.hibernate.type.array.ListArrayType import io.tolgee.api.IUserAccount import io.tolgee.api.SimpleUserAccount -import io.tolgee.model.slackIntegration.SlackConfig -import io.tolgee.model.slackIntegration.SlackUserConnection import io.tolgee.model.notifications.NotificationPreferences import io.tolgee.model.notifications.UserNotification +import io.tolgee.model.slackIntegration.SlackConfig +import io.tolgee.model.slackIntegration.SlackUserConnection import jakarta.persistence.CascadeType import jakarta.persistence.Column import jakarta.persistence.Entity diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt index 9f16b6f6df..64b4905a42 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt @@ -135,7 +135,7 @@ class ActivityEventListener( ActivityType.WEBHOOK_CONFIG_UPDATE, ActivityType.WEBHOOK_CONFIG_DELETE, ActivityType.HARD_DELETE_LANGUAGE, - null + null, -> {} } } From 59cf99c0a09743e5cb524339b5a9c5d70d5896fe Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Wed, 4 Sep 2024 17:47:40 +0200 Subject: [PATCH 42/44] feat: "Create Key" group items and their relations --- .../groups/dataProviders/CountsProvider.kt | 3 + .../groups/dataProviders/GroupDataProvider.kt | 42 +++++++++- .../PagedRelevantModifiedEntitiesProvider.kt | 36 +++++++++ .../RelevantModifiedEntitiesProvider.kt | 79 +++++++++---------- .../matchers/modifiedEntity/SqlContext.kt | 2 + .../keyCreate/CreateKeyGroupModelProvider.kt | 31 +++++++- 6 files changed, 149 insertions(+), 44 deletions(-) create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/PagedRelevantModifiedEntitiesProvider.kt diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/CountsProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/CountsProvider.kt index ab2b8e3e13..36e567b406 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/CountsProvider.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/CountsProvider.kt @@ -18,6 +18,7 @@ class CountsProvider( private val activityRevisionActivityGroupsTable = DSL.table("activity_revision_activity_groups").`as`("arag") private val groupIdField = DSL.field("arag.activity_groups_id", Long::class.java) private val countField = DSL.count() + private val entityIdField = DSL.field("ame.entity_id", Long::class.java) fun provide(): Map> { val sqlContext = @@ -25,6 +26,8 @@ class CountsProvider( modificationsField = DSL.field("ame.modifications", JSON::class.java), entityClassField = entityClassField, revisionTypeField = DSL.field("ame.revision_type", Int::class.java), + groupIdField = groupIdField, + entityIdField = entityIdField, ) val queryResult = diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/GroupDataProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/GroupDataProvider.kt index d644580935..11c3388c36 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/GroupDataProvider.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/GroupDataProvider.kt @@ -4,7 +4,9 @@ import com.fasterxml.jackson.databind.ObjectMapper import io.tolgee.activity.groups.ActivityGroupType import io.tolgee.activity.groups.data.ModifiedEntityView import io.tolgee.model.EntityWithId +import io.tolgee.model.StandardAuditModel import org.jooq.DSLContext +import org.jooq.impl.DSL import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable import org.springframework.stereotype.Component @@ -43,7 +45,7 @@ class GroupDataProvider( ): Page { val simpleNameString = entityClass.java.simpleName - return RelevantModifiedEntitiesProvider( + return PagedRelevantModifiedEntitiesProvider( jooqContext = jooqContext, objectMapper = objectMapper, groupType = groupType, @@ -52,4 +54,42 @@ class GroupDataProvider( pageable = pageable, ).provide() } + + fun getRelatedEntities( + entities: Page, + groupType: ActivityGroupType, + descriptionMapping: List, + groupId: Long, + ): List { + val entityClasses = descriptionMapping.map { it.entityClass }.toSet().map { it.java.simpleName } + + return RelevantModifiedEntitiesProvider( + jooqContext = jooqContext, + objectMapper = objectMapper, + groupType = groupType, + entityClasses = entityClasses, + additionalFilter = { context -> + DSL + .and( + context.groupIdField.eq(groupId), + ) + .and( + DSL.or( + descriptionMapping.flatMap { mapping -> + mapping.entityIds.map { + DSL.condition("(ame.describing_relations -> ? -> 'id')::bigint = ?", mapping.field, it) + .and(context.entityClassField.eq(mapping.entityClass.simpleName)) + } + }, + ), + ) + }, + ).provide() + } } + +data class DescriptionMapping( + val entityClass: KClass, + val field: String, + val entityIds: List, +) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/PagedRelevantModifiedEntitiesProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/PagedRelevantModifiedEntitiesProvider.kt new file mode 100644 index 0000000000..404f1ffaae --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/PagedRelevantModifiedEntitiesProvider.kt @@ -0,0 +1,36 @@ +package io.tolgee.activity.groups.dataProviders + +import com.fasterxml.jackson.databind.ObjectMapper +import io.tolgee.activity.groups.ActivityGroupType +import io.tolgee.activity.groups.data.ModifiedEntityView +import org.jooq.DSLContext +import org.jooq.impl.DSL +import org.springframework.data.domain.Page +import org.springframework.data.domain.PageImpl +import org.springframework.data.domain.Pageable + +class PagedRelevantModifiedEntitiesProvider( + jooqContext: DSLContext, + objectMapper: ObjectMapper, + groupType: ActivityGroupType, + entityClasses: List, + groupId: Long, + private val pageable: Pageable, +) { + private val baseProvider = + RelevantModifiedEntitiesProvider( + jooqContext = jooqContext, + objectMapper = objectMapper, + groupType = groupType, + entityClasses = entityClasses, + additionalFilter = { it.groupIdField.eq(groupId) }, + ) + + fun provide(): Page { + val count = getCountQuery().fetchOne(0, Int::class.java) ?: 0 + val content = baseProvider.provide(pageable) + return PageImpl(content, pageable, count.toLong()) + } + + private fun getCountQuery() = baseProvider.getQueryBase(DSL.count()) +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/RelevantModifiedEntitiesProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/RelevantModifiedEntitiesProvider.kt index 84b7863b7d..94ab964776 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/RelevantModifiedEntitiesProvider.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/RelevantModifiedEntitiesProvider.kt @@ -5,12 +5,11 @@ import com.fasterxml.jackson.module.kotlin.readValue import io.tolgee.activity.groups.ActivityGroupType import io.tolgee.activity.groups.data.ModifiedEntityView import io.tolgee.activity.groups.matchers.modifiedEntity.SqlContext +import org.jooq.Condition import org.jooq.DSLContext import org.jooq.JSON import org.jooq.SelectField import org.jooq.impl.DSL -import org.springframework.data.domain.Page -import org.springframework.data.domain.PageImpl import org.springframework.data.domain.Pageable class RelevantModifiedEntitiesProvider( @@ -18,58 +17,28 @@ class RelevantModifiedEntitiesProvider( private val objectMapper: ObjectMapper, private val groupType: ActivityGroupType, private val entityClasses: List, - private val groupId: Long, - private val pageable: Pageable, + private val additionalFilter: ((SqlContext) -> Condition)? = null, ) { private val activityModifiedEntityTable = DSL.table("activity_modified_entity").`as`("ame") - private val entityClassField = DSL.field("ame.entity_class", String::class.java) private val activityRevisionTable = DSL.table("activity_revision").`as`("ar") private val activityRevisionActivityGroupsTable = DSL.table("activity_revision_activity_groups").`as`("arag") private val groupIdField = DSL.field("arag.activity_groups_id", Long::class.java) + private val entityClassField = DSL.field("ame.entity_class", String::class.java) private val entityIdField = DSL.field("ame.entity_id", Long::class.java) private val describingDataField = DSL.field("ame.describing_data", JSON::class.java) private val describingRelationsField = DSL.field("ame.describing_relations", JSON::class.java) private val modificationsField = DSL.field("ame.modifications", JSON::class.java) + private val sqlContext = SqlContext( modificationsField = DSL.field("ame.modifications", JSON::class.java), entityClassField = entityClassField, revisionTypeField = DSL.field("ame.revision_type", Int::class.java), + groupIdField = groupIdField, + entityIdField = entityIdField, ) - fun provide(): Page { - val queryResult = - getDataQuery() - .fetch() - - val content = - queryResult.map { - ModifiedEntityView( - entityId = it.get(entityIdField)!!, - entityClass = it.get(entityClassField)!!, - describingData = objectMapper.readValue(it.get(describingDataField).data()), - describingRelations = objectMapper.readValue(it.get(describingRelationsField).data()), - modifications = objectMapper.readValue(it.get(modificationsField).data()), - ) - } - - val count = getCountQuery().fetchOne(0, Int::class.java) ?: 0 - - return PageImpl(content, pageable, count.toLong()) - } - - private fun getDataQuery() = - getQueryBase( - entityIdField, - entityClassField, - describingDataField, - describingRelationsField, - modificationsField, - ) - - private fun getCountQuery() = getQueryBase(DSL.count()) - - private fun getQueryBase(vararg fields: SelectField<*>) = + fun getQueryBase(vararg fields: SelectField<*>) = jooqContext .select(*fields) .from(activityModifiedEntityTable) @@ -84,8 +53,38 @@ class RelevantModifiedEntitiesProvider( .eq(DSL.field("arag.activity_revisions_id", Long::class.java)), ) .where( - groupIdField.`in`(groupId).and(entityClassField.`in`(entityClasses)).and( + DSL.and(entityClassField.`in`(entityClasses)).and( groupType.matcher?.match(sqlContext), - ), + ).and(additionalFilter?.let { it(sqlContext) } ?: DSL.noCondition()), ) + + private fun getDataQuery() = + getQueryBase( + entityIdField, + entityClassField, + describingDataField, + describingRelationsField, + modificationsField, + ) + + fun provide(pageable: Pageable? = null): List { + val query = + getDataQuery().also { query -> + pageable?.let { + query.limit(it.pageSize).offset(it.offset) + } + } + + val queryResult = query.fetch() + + return queryResult.map { + ModifiedEntityView( + entityId = it.get(entityIdField)!!, + entityClass = it.get(entityClassField)!!, + describingData = objectMapper.readValue(it.get(describingDataField).data()), + describingRelations = objectMapper.readValue(it.get(describingRelationsField).data()), + modifications = objectMapper.readValue(it.get(modificationsField).data()), + ) + } + } } diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/SqlContext.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/SqlContext.kt index 16f6647a61..ffea8ebd22 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/SqlContext.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/SqlContext.kt @@ -10,4 +10,6 @@ class SqlContext( val modificationsField: Field, var entityClassField: Field, var revisionTypeField: Field, + val groupIdField: Field, + val entityIdField: Field, ) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupModelProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupModelProvider.kt index 736491efdc..79ecaa7635 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupModelProvider.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupModelProvider.kt @@ -2,8 +2,11 @@ package io.tolgee.activity.groups.viewProviders.keyCreate import io.tolgee.activity.groups.ActivityGroupType import io.tolgee.activity.groups.GroupModelProvider +import io.tolgee.activity.groups.dataProviders.DescriptionMapping import io.tolgee.activity.groups.dataProviders.GroupDataProvider import io.tolgee.model.key.Key +import io.tolgee.model.key.KeyMeta +import io.tolgee.model.translation.Translation import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable import org.springframework.stereotype.Component @@ -36,15 +39,37 @@ class CreateKeyGroupModelProvider( pageable, ) + val entityIds = entities.map { it.entityId }.toList() + + val relatedEntities = + groupDataProvider.getRelatedEntities( + entities, + groupType = ActivityGroupType.CREATE_KEY, + groupId = groupId, + descriptionMapping = + listOf( + DescriptionMapping( + entityClass = KeyMeta::class, + field = "key", + entityIds = entityIds, + ), + DescriptionMapping( + entityClass = Translation::class, + field = "key", + entityIds = entityIds, + ), + ), + ) + return entities.map { CreateKeyGroupItemModel( it.entityId, - name = it.getFieldFromView("name"), + name = it.getFieldFromView(Key::name.name), tags = it.getFieldFromViewNullable("tags") ?: emptySet(), description = it.getFieldFromViewNullable("description"), custom = it.getFieldFromViewNullable("custom"), - isPlural = false, - pluralArgName = null, + isPlural = it.getFieldFromView("isPlural"), + pluralArgName = it.getFieldFromViewNullable("pluralArgName"), namespace = null, baseTranslationValue = null, ) From 59bc144137d91d2640027093258b26b36751b40f Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Sat, 14 Sep 2024 11:29:51 +0200 Subject: [PATCH 43/44] feat: Store base translation value for key --- .../ProjectActivityGroupItemsController.kt | 6 +- .../activity/ActivityAdditionalDescriber.kt | 10 ++ .../io/tolgee/activity/ActivityService.kt | 25 ++- .../KeyBaseTranslationDescriber.kt | 156 ++++++++++++++++++ .../activity/groups/ActivityGroupDto.kt | 1 + .../activity/groups/ActivityGroupService.kt | 34 +++- .../activity/groups/ActivityGroupType.kt | 130 +++++++++------ .../tolgee/activity/groups/ActivityGrouper.kt | 49 ++++-- .../activity/groups/ActivityGroupsProvider.kt | 18 +- .../activity/groups/GroupModelProvider.kt | 4 +- .../groups/data/DescribingEntityView.kt | 11 ++ .../activity/groups/data/DescribingMapping.kt | 9 + .../groups/data/ModifiedEntityView.kt | 10 +- .../activity/groups/data/RelatedMapping.kt | 10 ++ .../groups/dataProviders/CountsProvider.kt | 38 +++-- .../DescribingEntitiesProvider.kt | 79 +++++++++ .../groups/dataProviders/GroupDataProvider.kt | 83 ++++++---- .../RelevantModifiedEntitiesProvider.kt | 8 +- .../matchers/modifiedEntity/DefaultMatcher.kt | 13 +- .../modifiedEntity/MatchingStringProvider.kt | 9 + .../SetTranslationMatchingStringProvider.kt | 22 +++ .../matchers/modifiedEntity/SqlContext.kt | 3 +- .../matchers/modifiedEntity/StoringContext.kt | 2 + .../modifiedEntity/TranslationMatcher.kt | 70 ++++++++ .../CreateKeyGroupItemModel.kt | 5 +- .../createKey/CreateKeyGroupModel.kt | 5 + .../createKey/CreateKeyGroupModelProvider.kt | 111 +++++++++++++ .../CreateProjectGroupModelProvider.kt | 4 +- .../keyCreate/CreateKeyGroupModel.kt | 5 - .../keyCreate/CreateKeyGroupModelProvider.kt | 78 --------- .../SetTranslationsGroupItemModel.kt | 23 +++ .../SetTranslationsGroupModel.kt | 5 + .../SetTranslationsGroupModelProvider.kt | 37 +++++ .../iterceptor/InterceptedEventsManager.kt | 2 +- .../tolgee/api/ProjectIdAndBaseLanguageId.kt | 6 + .../io/tolgee/batch/ChunkProcessingUtil.kt | 8 +- .../demoProject/DemoProjectCreator.kt | 2 +- .../io/tolgee/dtos/cacheable/ProjectDto.kt | 5 +- .../main/kotlin/io/tolgee/model/Project.kt | 6 +- .../activity/ActivityDescribingEntity.kt | 8 +- .../activity/ActivityEntityWithDescription.kt | 20 +++ .../io/tolgee/model/activity/ActivityGroup.kt | 2 + .../model/activity/ActivityModifiedEntity.kt | 8 +- .../tolgee/model/activity/ActivityRevision.kt | 12 ++ .../main/kotlin/io/tolgee/model/key/Key.kt | 2 + .../activity/ActivityGroupRepository.kt | 3 + .../service/language/LanguageService.kt | 2 +- .../tolgee/service/project/ProjectService.kt | 2 +- .../main/resources/db/changelog/schema.xml | 20 +++ .../ProjectAuthorizationInterceptor.kt | 2 +- gradle/liquibase.gradle | 4 +- .../activity/groups/ActivityGroupItem.tsx | 3 + .../groups/SimpleTableExpandedContent.tsx | 68 ++++++++ .../CreateKeysActivityGroup.tsx | 56 ++----- .../SetTranslationsActivityGroup.tsx | 35 ++++ webapp/src/service/apiSchema.generated.ts | 148 +++++++++++------ 56 files changed, 1158 insertions(+), 339 deletions(-) create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/ActivityAdditionalDescriber.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/additionalDescribers/KeyBaseTranslationDescriber.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/data/DescribingEntityView.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/data/DescribingMapping.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/data/RelatedMapping.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/DescribingEntitiesProvider.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/MatchingStringProvider.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/SetTranslationMatchingStringProvider.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/TranslationMatcher.kt rename backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/{keyCreate => createKey}/CreateKeyGroupItemModel.kt (86%) create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createKey/CreateKeyGroupModel.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createKey/CreateKeyGroupModelProvider.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupModel.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupModelProvider.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/setTranslations/SetTranslationsGroupItemModel.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/setTranslations/SetTranslationsGroupModel.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/setTranslations/SetTranslationsGroupModelProvider.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/api/ProjectIdAndBaseLanguageId.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityEntityWithDescription.kt create mode 100644 webapp/src/component/activity/groups/SimpleTableExpandedContent.tsx create mode 100644 webapp/src/component/activity/groups/groupTypeComponents/SetTranslationsActivityGroup.tsx diff --git a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectActivityGroupItemsController.kt b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectActivityGroupItemsController.kt index 3a6d6a6a0d..cad75a1e84 100644 --- a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectActivityGroupItemsController.kt +++ b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectActivityGroupItemsController.kt @@ -6,8 +6,8 @@ package io.tolgee.api.v2.controllers import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.tags.Tag -import io.tolgee.activity.groups.viewProviders.keyCreate.CreateKeyGroupItemModel -import io.tolgee.activity.groups.viewProviders.keyCreate.CreateKeyGroupModelProvider +import io.tolgee.activity.groups.viewProviders.createKey.CreateKeyGroupItemModel +import io.tolgee.activity.groups.viewProviders.createKey.CreateKeyGroupModelProvider import io.tolgee.model.enums.Scope import io.tolgee.security.authentication.AllowApiAccess import io.tolgee.security.authorization.RequiresProjectPermissions @@ -40,7 +40,7 @@ class ProjectActivityGroupItemsController( @ParameterObject pageable: Pageable, @PathVariable groupId: Long, ): PagedModel { - val data = createKeyGroupModelProvider.provideItemModel(groupId, pageable) + val data = createKeyGroupModelProvider.provideItems(groupId, pageable) return PagedModel.of( data.content, PageMetadata(data.pageable.pageSize.toLong(), data.pageable.pageNumber.toLong(), data.totalElements), diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/ActivityAdditionalDescriber.kt b/backend/data/src/main/kotlin/io/tolgee/activity/ActivityAdditionalDescriber.kt new file mode 100644 index 0000000000..6a128061bb --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/ActivityAdditionalDescriber.kt @@ -0,0 +1,10 @@ +package io.tolgee.activity + +import io.tolgee.model.activity.ActivityRevision + +interface ActivityAdditionalDescriber { + fun describe( + activityRevision: ActivityRevision, + modifiedEntities: ModifiedEntitiesType, + ) +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/ActivityService.kt b/backend/data/src/main/kotlin/io/tolgee/activity/ActivityService.kt index 6fb8d261c0..6611bae64c 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/ActivityService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/ActivityService.kt @@ -33,6 +33,7 @@ class ActivityService( private val objectMapper: ObjectMapper, private val jdbcTemplate: JdbcTemplate, private val activityGroupService: ActivityGroupService, + private val describers: List, ) : Logging { @Transactional fun storeActivityData( @@ -42,8 +43,9 @@ class ActivityService( // let's keep the persistent context small entityManager.flushAndClear() - val mergedActivityRevision = persistActivityRevision(activityRevision) + runAdditionalDescribers(activityRevision, modifiedEntities) + val mergedActivityRevision = persistActivityRevision(activityRevision) persistedDescribingRelations(mergedActivityRevision) mergedActivityRevision.modifiedEntities = persistModifiedEntities(modifiedEntities) @@ -52,13 +54,22 @@ class ActivityService( applicationContext.publishEvent(OnProjectActivityStoredEvent(this, mergedActivityRevision)) } + private fun runAdditionalDescribers( + activityRevision: ActivityRevision, + modifiedEntities: ModifiedEntitiesType, + ) { + describers.forEach { + it.describe(activityRevision, modifiedEntities) + } + } + private fun persistModifiedEntities(modifiedEntities: ModifiedEntitiesType): MutableList { val list = modifiedEntities.values.flatMap { it.entries }.toMutableList() jdbcTemplate.batchUpdate( "INSERT INTO activity_modified_entity " + "(entity_class, entity_id, describing_data, " + - "describing_relations, modifications, revision_type, activity_revision_id) " + - "VALUES (?, ?, ?, ?, ?, ?, ?)", + "describing_relations, modifications, revision_type, activity_revision_id, additional_description) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?)", list, 100, ) { ps, (entityInstance, modifiedEntity) -> @@ -69,8 +80,9 @@ class ActivityService( ps.setObject(3, getJsonbObject(modifiedEntity.describingData)) ps.setObject(4, getJsonbObject(modifiedEntity.describingRelations)) ps.setObject(5, getJsonbObject(modifiedEntity.modifications)) - ps.setInt(6, RevisionType.values().indexOf(modifiedEntity.revisionType)) + ps.setInt(6, RevisionType.entries.indexOf(modifiedEntity.revisionType)) ps.setLong(7, modifiedEntity.activityRevision.id) + ps.setObject(8, getJsonbObject(modifiedEntity.additionalDescription)) } return list.map { it.value }.toMutableList() @@ -79,8 +91,8 @@ class ActivityService( private fun persistedDescribingRelations(activityRevision: ActivityRevision) { jdbcTemplate.batchUpdate( "INSERT INTO activity_describing_entity " + - "(entity_class, entity_id, data, describing_relations, activity_revision_id) " + - "VALUES (?, ?, ?, ?, ?)", + "(entity_class, entity_id, data, describing_relations, activity_revision_id, additional_description) " + + "VALUES (?, ?, ?, ?, ?, ?)", activityRevision.describingRelations, 100, ) { ps, entity -> @@ -89,6 +101,7 @@ class ActivityService( ps.setObject(3, getJsonbObject(entity.data)) ps.setObject(4, getJsonbObject(entity.describingRelations)) ps.setLong(5, activityRevision.id) + ps.setObject(6, getJsonbObject(entity.additionalDescription)) } } diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/additionalDescribers/KeyBaseTranslationDescriber.kt b/backend/data/src/main/kotlin/io/tolgee/activity/additionalDescribers/KeyBaseTranslationDescriber.kt new file mode 100644 index 0000000000..b3523c9cd2 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/additionalDescribers/KeyBaseTranslationDescriber.kt @@ -0,0 +1,156 @@ +package io.tolgee.activity.additionalDescribers + +import io.tolgee.activity.ActivityAdditionalDescriber +import io.tolgee.activity.ModifiedEntitiesType +import io.tolgee.activity.data.RevisionType +import io.tolgee.model.activity.ActivityDescribingEntity +import io.tolgee.model.activity.ActivityEntityWithDescription +import io.tolgee.model.activity.ActivityModifiedEntity +import io.tolgee.model.activity.ActivityRevision +import io.tolgee.model.key.Key +import io.tolgee.model.translation.Translation +import jakarta.persistence.EntityManager +import org.springframework.stereotype.Component + +@Component +class KeyBaseTranslationDescriber( + private val entityManager: EntityManager, +) : ActivityAdditionalDescriber { + companion object { + const val FIELD_NAME: String = "baseTranslation" + } + + override fun describe( + activityRevision: ActivityRevision, + modifiedEntities: ModifiedEntitiesType, + ) { + val relevantTranslationModifiedEntities = getRelevantModifiedEntities(activityRevision, modifiedEntities) + val relevantTranslationDescribingEntities = getRelevantDescribingEntities(activityRevision) + val toDescribe = getToDescribe(activityRevision, modifiedEntities) + val newKeyIds = + modifiedEntities[Key::class]?.mapNotNull { + if (it.value.revisionType == RevisionType.ADD) it.key.id else null + }?.toSet() ?: emptySet() + + toDescribe.removeIf { (id, entity) -> + // if entity is modified in current revision, we take it from there + relevantTranslationModifiedEntities[id]?.let { + entity.describe(getFromModifiedEntity(it)) + return@removeIf true + } + + // if entity is described in current revision, we take it from there + relevantTranslationDescribingEntities[id]?.let { + entity.describe(getFromDescribingEntity(it)) + return@removeIf true + } + + // if base value is not set for new key it doesn't make sense to search for it in the database + if (newKeyIds.contains(id)) { + entity.describe(null) + return@removeIf true + } + + false + } + + // other entities are taken from the database + describeRest(activityRevision, toDescribe) + } + + private fun ActivityEntityWithDescription.describe(baseText: String?) { + val additionalDescription = initAdditionalDescription() + additionalDescription[FIELD_NAME] = BaseTranslationDescription(baseText) + } + + private fun getToDescribe( + activityRevision: ActivityRevision, + allModifiedEntities: ModifiedEntitiesType, + ): MutableList> { + val describingRelations = + activityRevision.describingRelations.mapNotNull { + if (it.entityClass != "Key") return@mapNotNull null + it.entityId to it + } + + val modifiedEntities = allModifiedEntities[Key::class]?.map { it.key.id to it.value } ?: emptyList() + + return (describingRelations + modifiedEntities).toMutableList() + } + + private fun describeRest( + activityRevision: ActivityRevision, + toDescribe: MutableList>, + ) { + if (toDescribe.isEmpty()) { + return + } + + val keyIds = toDescribe.map { it.first } + val result = + entityManager.createQuery( + "select t.key.id, t.text from Translation t where t.key.id in :keyIds and t.language.id = :languageId", + Array::class.java, + ) + .setParameter("keyIds", keyIds.toSet()) + .setParameter("languageId", activityRevision.baseLanguageId) + .resultList + + return result.forEach { + val keyId = it[0] as Long + val text = it[1] as? String + toDescribe + .filter { (toDescribeId) -> toDescribeId == keyId } + .forEach { (_, entity) -> + entity.describe(text) + } + } + } + + private fun getFromDescribingEntity(it: ActivityDescribingEntity): String? { + return it.data["text"] as? String + } + + private fun getFromModifiedEntity(entity: ActivityModifiedEntity): String? { + val text = entity.modifications["text"]?.new ?: entity.describingData?.get("text") + return text as? String + } + + private fun getRelevantModifiedEntities( + activityRevision: ActivityRevision, + modifiedEntities: ModifiedEntitiesType, + ): Map { + val baseLanguageId = activityRevision.baseLanguageId + + return modifiedEntities[Translation::class]?.values?.mapNotNull { + val languageId = it.languageId ?: return@mapNotNull null + if (languageId != baseLanguageId) return@mapNotNull null + val keyId = it.keyId ?: return@mapNotNull null + keyId to it + }?.toMap() ?: emptyMap() + } + + private fun getRelevantDescribingEntities(activityRevision: ActivityRevision): Map { + val baseLanguageId = activityRevision.baseLanguageId + + return activityRevision.describingRelations.mapNotNull { + if (it.entityClass != "Translation") return@mapNotNull null + val languageId = it.languageId ?: return@mapNotNull null + if (languageId != baseLanguageId) return@mapNotNull null + val keyId = it.keyId ?: return@mapNotNull null + keyId to it + }.toMap() + } + + val ActivityEntityWithDescription.languageId: Long? + get() = + this.describingRelations?.get(Translation::language.name)?.entityId + + val ActivityEntityWithDescription.keyId: Long? + get() = + this.describingRelations?.get(Translation::key.name)?.entityId + + data class BaseTranslationDescription( + val text: String?, + ) +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupDto.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupDto.kt index 23227a593d..de19fcac4f 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupDto.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupDto.kt @@ -7,4 +7,5 @@ data class ActivityGroupDto( val activityGroupType: ActivityGroupType, val latestTimestamp: Date, val earliestTimestamp: Date, + val matchingString: String? = null, ) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupService.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupService.kt index 16b2ed4523..0fc74abd51 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupService.kt @@ -29,29 +29,36 @@ class ActivityGroupService( fun getOrCreateCurrentActivityGroupDto( type: ActivityGroupType, + matchingStrings: Set, projectId: Long?, authorId: Long?, - ): ActivityGroupDto { - val existing = findSuitableExistingSuitableGroupDto(type, projectId, authorId) - return existing ?: createActivityGroupDto(type, projectId, authorId) + ): Map { + return matchingStrings.associateWith { matchingString -> + val existing = findSuitableExistingSuitableGroupDto(type, matchingString, projectId, authorId) + val group = existing ?: createActivityGroupDto(type, matchingString, projectId, authorId) + group + } } private fun createActivityGroupDto( type: ActivityGroupType, + matchingString: String?, projectId: Long?, authorId: Long?, ): ActivityGroupDto { - val entity = createActivityGroup(type, projectId, authorId) + val entity = createActivityGroup(type, matchingString, projectId, authorId) return ActivityGroupDto( entity.id, entity.type, currentDateProvider.date, currentDateProvider.date, + matchingString = entity.matchingString, ) } private fun createActivityGroup( type: ActivityGroupType, + matchingString: String?, projectId: Long?, authorId: Long?, ): ActivityGroup { @@ -61,15 +68,17 @@ class ActivityGroupService( it.authorId = authorId it.projectId = projectId activityGroupRepository.saveAndFlush(it) + it.matchingString = matchingString } } private fun findSuitableExistingSuitableGroupDto( type: ActivityGroupType, + matchingString: String?, projectId: Long?, authorId: Long?, ): ActivityGroupDto? { - val latest = findLatest(type, authorId, projectId) ?: return null + val latest = findLatest(type, matchingString, authorId, projectId) ?: return null if (latest.isTooOld || latest.lastActivityTooEarly) { return null } @@ -78,12 +87,14 @@ class ActivityGroupService( private fun findLatest( type: ActivityGroupType, + matchingString: String?, authorId: Long?, projectId: Long?, ): ActivityGroupDto? { val result = activityGroupRepository.findLatest( groupTypeName = type.name, + matchingString = matchingString, authorId = authorId, projectId = projectId, ) @@ -94,12 +105,17 @@ class ActivityGroupService( val single = result.single() + return single.mapToGroupDto() + } + + private fun Array.mapToGroupDto(): ActivityGroupDto { return ActivityGroupDto( - single[0] as Long, - ActivityGroupType.valueOf(single[1] as String), + this[0] as Long, + ActivityGroupType.valueOf(this[1] as String), // if the group is empty we can just consider it as created now - single[2] as Date? ?: currentDateProvider.date, - single[3] as Date? ?: currentDateProvider.date, + this[3] as Date? ?: currentDateProvider.date, + this[4] as Date? ?: currentDateProvider.date, + matchingString = this[2] as String?, ) } diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupType.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupType.kt index 8ad8dd866f..5160bcb4cf 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupType.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupType.kt @@ -6,9 +6,13 @@ import io.tolgee.activity.groups.matchers.ActivityGroupValueMatcher.Companion.eq import io.tolgee.activity.groups.matchers.ActivityGroupValueMatcher.Companion.modification import io.tolgee.activity.groups.matchers.ActivityGroupValueMatcher.Companion.notNull import io.tolgee.activity.groups.matchers.modifiedEntity.DefaultMatcher +import io.tolgee.activity.groups.matchers.modifiedEntity.MatchingStringProvider import io.tolgee.activity.groups.matchers.modifiedEntity.ModifiedEntityMatcher +import io.tolgee.activity.groups.matchers.modifiedEntity.SetTranslationMatchingStringProvider +import io.tolgee.activity.groups.matchers.modifiedEntity.TranslationMatcher +import io.tolgee.activity.groups.viewProviders.createKey.CreateKeyGroupModelProvider import io.tolgee.activity.groups.viewProviders.createProject.CreateProjectGroupModelProvider -import io.tolgee.activity.groups.viewProviders.keyCreate.CreateKeyGroupModelProvider +import io.tolgee.activity.groups.viewProviders.setTranslations.SetTranslationsGroupModelProvider import io.tolgee.model.Language import io.tolgee.model.Project import io.tolgee.model.Screenshot @@ -29,7 +33,55 @@ enum class ActivityGroupType( val sourceActivityTypes: List, val modelProviderFactoryClass: KClass>? = null, val matcher: ModifiedEntityMatcher? = null, + val matchingStringProvider: MatchingStringProvider? = null, + /** + * Even if we are working with same revisions order can be unnatural in some cases. + * e.g. when user creates a key and then sets translations for it. It results in multiple groups. + * We need to force the order, so key creation is always before translation set + */ + val orderAfter: ActivityGroupType? = null, ) { + CREATE_KEY( + listOf(ActivityType.CREATE_KEY), + matcher = + DefaultMatcher( + entityClass = Key::class, + revisionTypes = listOf(RevisionType.ADD), + ).or( + DefaultMatcher( + entityClass = KeyMeta::class, + revisionTypes = listOf(RevisionType.ADD), + ), + ).or( + TranslationMatcher(TranslationMatcher.Type.BASE), + ), + modelProviderFactoryClass = CreateKeyGroupModelProvider::class, + ), + + EDIT_KEY_NAME( + listOf(ActivityType.KEY_NAME_EDIT, ActivityType.COMPLEX_EDIT), + matcher = + DefaultMatcher( + entityClass = Key::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(Key::name, Key::namespace), + ).or( + DefaultMatcher( + entityClass = Namespace::class, + revisionTypes = listOf(RevisionType.ADD, RevisionType.DEL), + ), + ), + ), + + DELETE_KEY( + listOf(ActivityType.KEY_DELETE), + matcher = + DefaultMatcher( + entityClass = Key::class, + revisionTypes = listOf(RevisionType.DEL), + ), + ), + SET_TRANSLATION_STATE( listOf(ActivityType.SET_TRANSLATION_STATE, ActivityType.COMPLEX_EDIT), matcher = @@ -55,14 +107,19 @@ enum class ActivityGroupType( ), ), - SET_TRANSLATIONS( + SET_BASE_TRANSLATION( listOf(ActivityType.SET_TRANSLATIONS, ActivityType.COMPLEX_EDIT), matcher = - DefaultMatcher( - entityClass = Translation::class, - revisionTypes = listOf(RevisionType.ADD, RevisionType.DEL, RevisionType.MOD), - modificationProps = listOf(Translation::text), - ), + TranslationMatcher(TranslationMatcher.Type.BASE), + ), + + SET_TRANSLATIONS( + listOf(ActivityType.SET_TRANSLATIONS, ActivityType.COMPLEX_EDIT, ActivityType.CREATE_KEY), + matcher = + TranslationMatcher(TranslationMatcher.Type.NON_BASE), + matchingStringProvider = SetTranslationMatchingStringProvider(), + modelProviderFactoryClass = SetTranslationsGroupModelProvider::class, + orderAfter = CREATE_KEY, ), DISMISS_AUTO_TRANSLATED_STATE( @@ -177,50 +234,6 @@ enum class ActivityGroupType( ), ), - EDIT_KEY_NAME( - listOf(ActivityType.KEY_NAME_EDIT, ActivityType.COMPLEX_EDIT), - matcher = - DefaultMatcher( - entityClass = Key::class, - revisionTypes = listOf(RevisionType.MOD), - modificationProps = listOf(Key::name, Key::namespace), - ).or( - DefaultMatcher( - entityClass = Namespace::class, - revisionTypes = listOf(RevisionType.ADD, RevisionType.DEL), - ), - ), - ), - - DELETE_KEY( - listOf(ActivityType.KEY_DELETE), - matcher = - DefaultMatcher( - entityClass = Key::class, - revisionTypes = listOf(RevisionType.DEL), - ), - ), - - CREATE_KEY( - listOf(ActivityType.CREATE_KEY), - matcher = - DefaultMatcher( - entityClass = Key::class, - revisionTypes = listOf(RevisionType.ADD), - ).or( - DefaultMatcher( - entityClass = KeyMeta::class, - revisionTypes = listOf(RevisionType.ADD), - ), - ).or( - DefaultMatcher( - Translation::class, - listOf(RevisionType.ADD), - ), - ), - modelProviderFactoryClass = CreateKeyGroupModelProvider::class, - ), - IMPORT( listOf(ActivityType.IMPORT), ), @@ -459,4 +472,19 @@ enum class ActivityGroupType( return groupType to itemType } + + companion object { + fun getOrderedTypes(): List { + val withType = ActivityGroupType.entries.filter { it.orderAfter != null } + val referenced = withType.mapNotNull { it.orderAfter } + val all = (withType + referenced).toSet() + return all.sortedWith { a, b -> + when { + a.orderAfter == b -> 1 + b.orderAfter == a -> -1 + else -> 0 + } + } + } + } } diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGrouper.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGrouper.kt index 6620dafc6f..552a72f1a6 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGrouper.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGrouper.kt @@ -2,6 +2,7 @@ package io.tolgee.activity.groups import io.tolgee.activity.ModifiedEntitiesType import io.tolgee.activity.groups.matchers.modifiedEntity.StoringContext +import io.tolgee.model.activity.ActivityModifiedEntity import io.tolgee.model.activity.ActivityRevision import jakarta.persistence.EntityManager import org.springframework.context.ApplicationContext @@ -13,9 +14,10 @@ class ActivityGrouper( ) { fun addToGroup() { val groupTypes = findGroupTypes() - groupTypes.forEach { - val groupIdToAddTo = getActivityGroupId(it) - addToGroup(groupIdToAddTo) + groupTypes.forEach { (type, matchingStrings) -> + getActivityGroupIds(type, matchingStrings).forEach { group -> + addToGroup(group.value) + } } } @@ -31,31 +33,52 @@ class ActivityGrouper( .executeUpdate() } - private fun getActivityGroupId(type: ActivityGroupType): Long { + private fun getActivityGroupIds( + type: ActivityGroupType, + matchingStrings: Set, + ): Map { return activityGroupService.getOrCreateCurrentActivityGroupDto( type, + matchingStrings, activityRevision.projectId, activityRevision.authorId, - ).id + ).mapValues { it.value.id } } - private fun findGroupTypes(): List { - return ActivityGroupType.entries.filter { it.matches } + private fun findGroupTypes(): Map> { + return ActivityGroupType.entries.mapNotNull { activityGroupType -> + val matchingEntities = activityGroupType.matchingEntities + if (matchingEntities.isEmpty()) { + return@mapNotNull null + } + activityGroupType to + activityGroupType.matchingEntities.map { entity -> + activityGroupType.matchingStringProvider?.provide( + entity.getStoringContext(), + ) + }.toSet() + }.toMap() } - private val ActivityGroupType.matches: Boolean + private val ActivityGroupType.matchingEntities: List get() { if (!this.sourceActivityTypes.contains(type)) { - return false + return emptyList() } - return modifiedEntities.any { modifiedEntityEntry -> - modifiedEntityEntry.value.values.any { modifiedEntity -> - this.matcher?.match(StoringContext(modifiedEntity)) ?: true - } + return modifiedEntities.values.flatMap { + it.values.filter { entity -> entityMatches(entity) } } } + private fun ActivityGroupType.entityMatches(entity: ActivityModifiedEntity): Boolean { + return this.matcher?.match(entity.getStoringContext()) ?: true + } + + private fun ActivityModifiedEntity.getStoringContext(): StoringContext { + return StoringContext(this, activityRevision) + } + private val type = activityRevision.type private val activityGroupService by lazy { diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupsProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupsProvider.kt index de0834fe89..fec3490312 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupsProvider.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/ActivityGroupsProvider.kt @@ -5,6 +5,7 @@ import com.fasterxml.jackson.module.kotlin.readValue import io.tolgee.api.SimpleUserAccount import io.tolgee.dtos.queryResults.ActivityGroupView import io.tolgee.dtos.request.ActivityGroupFilters +import org.jooq.CaseWhenStep import org.jooq.DSLContext import org.jooq.JSON import org.jooq.impl.DSL @@ -85,7 +86,7 @@ class ActivityGroupsProvider( .where(where) .groupBy(field("ag.id"), field("ua.id")) .having(having) - .orderBy(max(field("ar.timestamp")).desc()) + .orderBy(max(field("ar.timestamp")).desc(), orderedTypesField?.desc()) .limit(pageable.pageSize) .offset(pageable.offset).fetch().map { ActivityGroupView( @@ -122,7 +123,7 @@ class ActivityGroupsProvider( byType.flatMap { (type, items) -> val provider = type.modelProviderFactoryClass?.let { applicationContext.getBean(it.java) } - provider?.provideGroupModel(items.map { it.id })?.map { it.key to it.value } ?: emptyList() + provider?.provideGroup(items.map { it.id })?.map { it.key to it.value } ?: emptyList() }.toMap() } @@ -131,4 +132,17 @@ class ActivityGroupsProvider( private val jooqContext = applicationContext.getBean(DSLContext::class.java) private val objectMapper = applicationContext.getBean(ObjectMapper::class.java) + + private val orderedTypesField by lazy { + val choose = DSL.choose(field("ag.type")) + var whenStep: CaseWhenStep? = null + ActivityGroupType.getOrderedTypes().mapIndexed { index, type -> + whenStep?.let { + whenStep = it.`when`(type.name, index) + } ?: let { + whenStep = choose.`when`(type.name, index) + } + } + whenStep?.otherwise(0) + } } diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/GroupModelProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/GroupModelProvider.kt index ea6fef7727..973495964a 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/GroupModelProvider.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/GroupModelProvider.kt @@ -4,9 +4,9 @@ import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable interface GroupModelProvider { - fun provideGroupModel(groupIds: List): Map + fun provideGroup(groupIds: List): Map - fun provideItemModel( + fun provideItems( groupId: Long, pageable: Pageable, ): Page diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/DescribingEntityView.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/DescribingEntityView.kt new file mode 100644 index 0000000000..69c1ac816d --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/DescribingEntityView.kt @@ -0,0 +1,11 @@ +package io.tolgee.activity.groups.data + +import io.tolgee.activity.data.EntityDescriptionRef + +class DescribingEntityView( + val entityId: Long, + val entityClass: String, + val data: Map, + val describingRelations: Map, + val activityRevisionId: Long, +) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/DescribingMapping.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/DescribingMapping.kt new file mode 100644 index 0000000000..0b69c1fe81 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/DescribingMapping.kt @@ -0,0 +1,9 @@ +package io.tolgee.activity.groups.data + +import io.tolgee.model.StandardAuditModel +import kotlin.reflect.KClass + +data class DescribingMapping( + val entityClass: KClass, + val field: String, +) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/ModifiedEntityView.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/ModifiedEntityView.kt index 59b430f31f..6eb262f640 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/ModifiedEntityView.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/ModifiedEntityView.kt @@ -1,20 +1,16 @@ package io.tolgee.activity.groups.data +import io.tolgee.activity.data.EntityDescriptionRef import io.tolgee.activity.data.PropertyModification class ModifiedEntityView( val entityId: Long, val entityClass: String, val describingData: Map, - val describingRelations: Map, + val describingRelations: Map, val modifications: Map, + val activityRevisionId: Long, ) { - private inline fun Map.getFieldFromMap(name: String): T? { - this[name].let { - return it as? T - } - } - inline fun getFieldFromViewNullable(name: String): T? { return this.describingData[name] as? T ?: this.modifications[name]?.let { it.new as? T } } diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/RelatedMapping.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/RelatedMapping.kt new file mode 100644 index 0000000000..985e4faf7a --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/RelatedMapping.kt @@ -0,0 +1,10 @@ +package io.tolgee.activity.groups.data + +import io.tolgee.model.StandardAuditModel +import kotlin.reflect.KClass + +data class RelatedMapping( + val entityClass: KClass, + val field: String, + val entities: Iterable, +) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/CountsProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/CountsProvider.kt index 36e567b406..093ba08583 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/CountsProvider.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/CountsProvider.kt @@ -2,6 +2,7 @@ package io.tolgee.activity.groups.dataProviders import io.tolgee.activity.groups.ActivityGroupType import io.tolgee.activity.groups.matchers.modifiedEntity.SqlContext +import org.jooq.Condition import org.jooq.DSLContext import org.jooq.JSON import org.jooq.impl.DSL @@ -16,20 +17,11 @@ class CountsProvider( private val entityClassField = DSL.field("ame.entity_class", String::class.java) private val activityRevisionTable = DSL.table("activity_revision").`as`("ar") private val activityRevisionActivityGroupsTable = DSL.table("activity_revision_activity_groups").`as`("arag") + private val activityGroupTable = DSL.table("activity_group").`as`("ag") private val groupIdField = DSL.field("arag.activity_groups_id", Long::class.java) private val countField = DSL.count() - private val entityIdField = DSL.field("ame.entity_id", Long::class.java) fun provide(): Map> { - val sqlContext = - SqlContext( - modificationsField = DSL.field("ame.modifications", JSON::class.java), - entityClassField = entityClassField, - revisionTypeField = DSL.field("ame.revision_type", Int::class.java), - groupIdField = groupIdField, - entityIdField = entityIdField, - ) - val queryResult = jooqContext .select( @@ -48,10 +40,14 @@ class CountsProvider( DSL.field("ar.id", Long::class.java) .eq(DSL.field("arag.activity_revisions_id", Long::class.java)), ) + .join(activityGroupTable).on( + groupIdField.eq(DSL.field("ag.id", Long::class.java)), + ) .where( - groupIdField.`in`(groupIds).and(entityClassField.`in`(entityClasses)).and( - groupType.matcher?.match(sqlContext), - ), + groupIdField.`in`(groupIds) + .and(entityClassField.`in`(entityClasses)) + .and(groupType.matcher?.match(sqlContext)) + .and(getStringMatcherCondition()), ) .groupBy(entityClassField, groupIdField) .fetch() @@ -60,4 +56,20 @@ class CountsProvider( rows.value.associate { entityClassField.getValue(it)!! to countField.getValue(it)!! } } } + + private val sqlContext by lazy { + SqlContext( + modificationsField = DSL.field("ame.modifications", JSON::class.java), + entityClassField = entityClassField, + revisionTypeField = DSL.field("ame.revision_type", Int::class.java), + groupIdField = groupIdField, + baseLanguageField = DSL.field("ar.base_language_id", Long::class.java), + describingRelationsField = DSL.field("ame.describing_relations", JSON::class.java), + ) + } + + private fun getStringMatcherCondition(): Condition { + return groupType.matchingStringProvider?.provide(sqlContext) + ?.eq(DSL.field("ag.matching_string", String::class.java)) ?: DSL.noCondition() + } } diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/DescribingEntitiesProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/DescribingEntitiesProvider.kt new file mode 100644 index 0000000000..101bf87d31 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/DescribingEntitiesProvider.kt @@ -0,0 +1,79 @@ +package io.tolgee.activity.groups.dataProviders + +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue +import io.tolgee.activity.groups.data.DescribingEntityView +import io.tolgee.activity.groups.data.DescribingMapping +import io.tolgee.activity.groups.data.ModifiedEntityView +import org.jooq.DSLContext +import org.jooq.JSON +import org.jooq.impl.DSL + +class DescribingEntitiesProvider( + private val jooqContext: DSLContext, + private val objectMapper: ObjectMapper, + private val describingMapping: List, + private val entities: Iterable, +) { + private val describingEntityTable = DSL.table("activity_describing_entity").`as`("ade") + private val entityIdField = DSL.field("ade.entity_id", Long::class.java) + private val entityClassField = DSL.field("ade.entity_class", String::class.java) + private val dataField = DSL.field("ade.data", JSON::class.java) + private val describingRelationsField = DSL.field("ade.describing_relations", JSON::class.java) + private val activityRevisionIdField = DSL.field("ade.activity_revision_id", Long::class.java) + + fun provide(): Map> { + val views = + query.fetch() + .map { + DescribingEntityView( + entityId = it.get(entityIdField), + entityClass = it.get(entityClassField), + data = objectMapper.readValue(it.get(dataField).data()), + describingRelations = objectMapper.readValue(it.get(describingRelationsField).data()), + activityRevisionId = it.get(activityRevisionIdField), + ) + } + + val grouped = refs.groupBy { it.first } + + return grouped.mapValues { (_, refs) -> + refs.mapNotNull { (entity, ref) -> + views.find { + it.entityId == ref.entityId && + it.entityClass == ref.entityClass && + it.activityRevisionId == entity.activityRevisionId + } + } + } + } + + val query by lazy { + jooqContext + .select(entityIdField, entityClassField, dataField, describingRelationsField, activityRevisionIdField) + .from(describingEntityTable) + .where(condition) + } + + val condition by lazy { + DSL.or( + refs.map { (entity, ref) -> + DSL.condition(entityClassField.eq(ref.entityClass)) + .and(entityIdField.eq(ref.entityId)) + .and(activityRevisionIdField.eq(entity.activityRevisionId)) + }, + ) + } + + private val refs by lazy { + describingMapping.flatMap { mapping -> + entities.mapNotNull { entity -> + if (entity.entityClass != mapping.entityClass.simpleName) { + return@mapNotNull null + } + val ref = entity.describingRelations[mapping.field] ?: return@mapNotNull null + return@mapNotNull entity to ref + } + } + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/GroupDataProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/GroupDataProvider.kt index 11c3388c36..1e10b743e4 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/GroupDataProvider.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/GroupDataProvider.kt @@ -2,9 +2,11 @@ package io.tolgee.activity.groups.dataProviders import com.fasterxml.jackson.databind.ObjectMapper import io.tolgee.activity.groups.ActivityGroupType +import io.tolgee.activity.groups.data.DescribingEntityView +import io.tolgee.activity.groups.data.DescribingMapping import io.tolgee.activity.groups.data.ModifiedEntityView +import io.tolgee.activity.groups.data.RelatedMapping import io.tolgee.model.EntityWithId -import io.tolgee.model.StandardAuditModel import org.jooq.DSLContext import org.jooq.impl.DSL import org.springframework.data.domain.Page @@ -56,40 +58,61 @@ class GroupDataProvider( } fun getRelatedEntities( - entities: Page, groupType: ActivityGroupType, - descriptionMapping: List, + relatedMappings: List, groupId: Long, - ): List { - val entityClasses = descriptionMapping.map { it.entityClass }.toSet().map { it.java.simpleName } + ): Map>> { + val entityClasses = relatedMappings.map { it.entityClass }.toSet().map { it.java.simpleName } - return RelevantModifiedEntitiesProvider( + val entities = + RelevantModifiedEntitiesProvider( + jooqContext = jooqContext, + objectMapper = objectMapper, + groupType = groupType, + entityClasses = entityClasses, + additionalFilter = { context -> + DSL + .and( + context.groupIdField.eq(groupId), + ) + .and( + DSL.or( + relatedMappings.flatMap { mapping -> + mapping.entities.map { + DSL.condition( + "(${context.describingRelationsField.name} -> ? -> 'entityId')::bigint = ?", + mapping.field, + it.entityId, + ) + .and(context.entityClassField.eq(mapping.entityClass.simpleName)) + } + }, + ), + ) + }, + ).provide() + + val allParents = relatedMappings.flatMap { it.entities } + + return allParents.associateWith { parent -> + relatedMappings.associateWith { mapping -> + entities.filter { entity -> + entity.entityClass == mapping.entityClass.simpleName && + entity.describingRelations.any { mapping.field == it.key && it.value?.entityId == parent.entityId } + } + } + } + } + + fun getDescribingEntities( + entities: Iterable, + describingMapping: List, + ): Map> { + return DescribingEntitiesProvider( + entities = entities, jooqContext = jooqContext, objectMapper = objectMapper, - groupType = groupType, - entityClasses = entityClasses, - additionalFilter = { context -> - DSL - .and( - context.groupIdField.eq(groupId), - ) - .and( - DSL.or( - descriptionMapping.flatMap { mapping -> - mapping.entityIds.map { - DSL.condition("(ame.describing_relations -> ? -> 'id')::bigint = ?", mapping.field, it) - .and(context.entityClassField.eq(mapping.entityClass.simpleName)) - } - }, - ), - ) - }, + describingMapping = describingMapping, ).provide() } } - -data class DescriptionMapping( - val entityClass: KClass, - val field: String, - val entityIds: List, -) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/RelevantModifiedEntitiesProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/RelevantModifiedEntitiesProvider.kt index 94ab964776..78a3def657 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/RelevantModifiedEntitiesProvider.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/RelevantModifiedEntitiesProvider.kt @@ -28,6 +28,7 @@ class RelevantModifiedEntitiesProvider( private val describingDataField = DSL.field("ame.describing_data", JSON::class.java) private val describingRelationsField = DSL.field("ame.describing_relations", JSON::class.java) private val modificationsField = DSL.field("ame.modifications", JSON::class.java) + private val activityRevisionId = DSL.field("ame.activity_revision_id", Long::class.java) private val sqlContext = SqlContext( @@ -35,7 +36,8 @@ class RelevantModifiedEntitiesProvider( entityClassField = entityClassField, revisionTypeField = DSL.field("ame.revision_type", Int::class.java), groupIdField = groupIdField, - entityIdField = entityIdField, + baseLanguageField = DSL.field("ar.base_language_id", Long::class.java), + describingRelationsField = describingRelationsField, ) fun getQueryBase(vararg fields: SelectField<*>) = @@ -65,11 +67,12 @@ class RelevantModifiedEntitiesProvider( describingDataField, describingRelationsField, modificationsField, + activityRevisionId, ) fun provide(pageable: Pageable? = null): List { val query = - getDataQuery().also { query -> + getDataQuery().orderBy(activityRevisionId.desc()).also { query -> pageable?.let { query.limit(it.pageSize).offset(it.offset) } @@ -84,6 +87,7 @@ class RelevantModifiedEntitiesProvider( describingData = objectMapper.readValue(it.get(describingDataField).data()), describingRelations = objectMapper.readValue(it.get(describingRelationsField).data()), modifications = objectMapper.readValue(it.get(modificationsField).data()), + activityRevisionId = activityRevisionId.get(it)!!, ) } } diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/DefaultMatcher.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/DefaultMatcher.kt index e0e6a5e4c4..c67027611c 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/DefaultMatcher.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/DefaultMatcher.kt @@ -79,8 +79,13 @@ class DefaultMatcher( private fun getModificationPropsCondition(context: SqlContext): Condition { if (modificationProps != null) { - return DSL.condition( - "array(select jsonb_object_keys(${context.modificationsField.name})) && ${allowedModString()}", + val props = modificationProps.map { it.name }.toTypedArray() + return DSL.arrayOverlap( + DSL.field( + "array(select jsonb_object_keys(${context.modificationsField.name}))::varchar[]", + Array::class.java, + ), + props, ) } return DSL.noCondition() @@ -94,8 +99,8 @@ class DefaultMatcher( return context.entityClassField.eq(entityClass.simpleName) } - private fun allowedModString(): String { - return "{${modificationProps?.joinToString(",")}}" + private fun getAllowedModString(): String { + return "{${modificationProps?.joinToString(",") { "'${it.name}'" }}}" } private fun getAllowedValuesCondition(context: SqlContext): Condition { diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/MatchingStringProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/MatchingStringProvider.kt new file mode 100644 index 0000000000..8bb94bf8ec --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/MatchingStringProvider.kt @@ -0,0 +1,9 @@ +package io.tolgee.activity.groups.matchers.modifiedEntity + +import org.jooq.Field + +interface MatchingStringProvider { + fun provide(context: StoringContext): String? + + fun provide(context: SqlContext): Field? +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/SetTranslationMatchingStringProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/SetTranslationMatchingStringProvider.kt new file mode 100644 index 0000000000..b37979635d --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/SetTranslationMatchingStringProvider.kt @@ -0,0 +1,22 @@ +package io.tolgee.activity.groups.matchers.modifiedEntity + +import io.tolgee.model.translation.Translation +import org.jooq.Field +import org.jooq.impl.DSL + +class SetTranslationMatchingStringProvider : MatchingStringProvider { + override fun provide(context: StoringContext): String? { + if (context.modifiedEntity.entityClass != Translation::class.simpleName) { + return null + } + return context.modifiedEntity.describingRelations?.get("language")?.entityId?.toString() + ?: throw IllegalStateException("Language not found") + } + + override fun provide(context: SqlContext): Field { + return DSL.field( + "(${context.describingRelationsField.name} -> 'language' -> 'entityId')::varchar", + String::class.java, + ) + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/SqlContext.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/SqlContext.kt index ffea8ebd22..10ed5f84f7 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/SqlContext.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/SqlContext.kt @@ -11,5 +11,6 @@ class SqlContext( var entityClassField: Field, var revisionTypeField: Field, val groupIdField: Field, - val entityIdField: Field, + val describingRelationsField: Field, + val baseLanguageField: Field, ) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/StoringContext.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/StoringContext.kt index 598f53973a..b4f22c751e 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/StoringContext.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/StoringContext.kt @@ -1,10 +1,12 @@ package io.tolgee.activity.groups.matchers.modifiedEntity import io.tolgee.model.activity.ActivityModifiedEntity +import io.tolgee.model.activity.ActivityRevision /** * This is all the context that is provided when storing the activity data */ class StoringContext( val modifiedEntity: ActivityModifiedEntity, + val activityRevision: ActivityRevision, ) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/TranslationMatcher.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/TranslationMatcher.kt new file mode 100644 index 0000000000..086566710a --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/matchers/modifiedEntity/TranslationMatcher.kt @@ -0,0 +1,70 @@ +package io.tolgee.activity.groups.matchers.modifiedEntity + +import io.tolgee.activity.data.RevisionType +import io.tolgee.model.translation.Translation +import org.jooq.Condition +import org.jooq.impl.DSL + +class TranslationMatcher( + private val type: Type = Type.BASE, +) : ModifiedEntityMatcher { + private val defaultMatcher by lazy { + DefaultMatcher( + entityClass = Translation::class, + revisionTypes = listOf(RevisionType.ADD, RevisionType.MOD), + modificationProps = listOf(Translation::text), + ) + } + + override fun match(context: StoringContext): Boolean { + if (!defaultMatcher.match(context)) { + return false + } + + if (type == Type.ANY) { + return true + } + + val entityId = + context.modifiedEntity.describingRelations?.get("language")?.entityId + // non-base is the default, so we return true if it is not base translation + ?: return type == Type.NON_BASE + + val isBase = context.activityRevision.baseLanguageId == entityId + + if (type == Type.BASE) { + return isBase + } + + return !isBase + } + + override fun match(context: SqlContext): Condition { + val baseCondition = defaultMatcher.match(context) + + if (type == Type.ANY) { + return baseCondition + } + + val baseLanguageCondition = context.getSqlCondition() + + if (type == Type.BASE) { + return baseCondition.and(baseLanguageCondition) + } + + return baseCondition.and(baseLanguageCondition.not()) + } + + private fun SqlContext.getSqlCondition(): Condition { + val sqlCondition = + "(${describingRelationsField.name} -> 'language' -> 'entityId')::bigint = ${baseLanguageField.name}" + + return DSL.condition(sqlCondition) + } + + enum class Type { + BASE, + NON_BASE, + ANY, + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupItemModel.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createKey/CreateKeyGroupItemModel.kt similarity index 86% rename from backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupItemModel.kt rename to backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createKey/CreateKeyGroupItemModel.kt index a37a00eb45..d7d426c8bd 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupItemModel.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createKey/CreateKeyGroupItemModel.kt @@ -1,4 +1,4 @@ -package io.tolgee.activity.groups.viewProviders.keyCreate +package io.tolgee.activity.groups.viewProviders.createKey import io.swagger.v3.oas.annotations.media.Schema import io.tolgee.api.IKeyModel @@ -16,7 +16,8 @@ class CreateKeyGroupItemModel( val pluralArgName: String?, @Schema(description = "The base translation value entered when key was created") val baseTranslationValue: String?, - val tags: Set, + val tags: List, override val description: String?, override val custom: Map?, + val baseLanguageId: Long?, ) : IKeyModel diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createKey/CreateKeyGroupModel.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createKey/CreateKeyGroupModel.kt new file mode 100644 index 0000000000..04083fa011 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createKey/CreateKeyGroupModel.kt @@ -0,0 +1,5 @@ +package io.tolgee.activity.groups.viewProviders.createKey + +class CreateKeyGroupModel( + val keyCount: Int, +) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createKey/CreateKeyGroupModelProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createKey/CreateKeyGroupModelProvider.kt new file mode 100644 index 0000000000..da9c4264bb --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createKey/CreateKeyGroupModelProvider.kt @@ -0,0 +1,111 @@ +package io.tolgee.activity.groups.viewProviders.createKey + +import io.tolgee.activity.groups.ActivityGroupType +import io.tolgee.activity.groups.GroupModelProvider +import io.tolgee.activity.groups.data.DescribingMapping +import io.tolgee.activity.groups.data.RelatedMapping +import io.tolgee.activity.groups.dataProviders.GroupDataProvider +import io.tolgee.model.key.Key +import io.tolgee.model.key.KeyMeta +import io.tolgee.model.key.Namespace +import io.tolgee.model.translation.Translation +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.stereotype.Component + +@Component +class CreateKeyGroupModelProvider( + private val groupDataProvider: GroupDataProvider, +) : + GroupModelProvider { + override fun provideGroup(groupIds: List): Map { + val keyCounts = + groupDataProvider.provideCounts(ActivityGroupType.CREATE_KEY, groupIds = groupIds, entityClass = Key::class) + + return groupIds.associateWith { + CreateKeyGroupModel( + keyCounts[it] ?: 0, + ) + } + } + + override fun provideItems( + groupId: Long, + pageable: Pageable, + ): Page { + val entities = + groupDataProvider.provideRelevantModifiedEntities( + ActivityGroupType.CREATE_KEY, + Key::class, + groupId, + pageable, + ) + + val translationMapping = + RelatedMapping( + entityClass = Translation::class, + field = "key", + entities, + ) + + val keyMetaMapping = + RelatedMapping( + entityClass = KeyMeta::class, + field = "key", + entities, + ) + + val relatedEntities = + groupDataProvider.getRelatedEntities( + groupType = ActivityGroupType.CREATE_KEY, + relatedMappings = + listOf( + keyMetaMapping, + translationMapping, + ), + groupId = groupId, + ) + + val descriptions = + groupDataProvider.getDescribingEntities( + entities, + listOf(DescribingMapping(Key::class, Key::namespace.name)), + ) + + return entities.map { entity -> + val baseTranslation = + relatedEntities[entity] + ?.get(translationMapping)?.singleOrNull() + + val baseTranslationValue = + baseTranslation?.modifications + ?.get("text") + ?.new as? String + + val baseLanguageId = baseTranslation?.describingRelations?.get("language")?.entityId + + val keyMeta = + relatedEntities[entity] + ?.get(keyMetaMapping) + ?.singleOrNull() + + CreateKeyGroupItemModel( + entity.entityId, + name = entity.getFieldFromView(Key::name.name), + tags = (keyMeta?.getFieldFromViewNullable(KeyMeta::tags.name) as? List) ?: emptyList(), + description = keyMeta?.getFieldFromViewNullable(KeyMeta::description.name), + custom = keyMeta?.getFieldFromViewNullable(KeyMeta::custom.name), + isPlural = entity.getFieldFromView(Key::isPlural.name), + pluralArgName = entity.getFieldFromViewNullable(Key::pluralArgName.name), + namespace = + descriptions[entity] + ?.find { it.entityClass == Namespace::class.simpleName } + ?.data + ?.get(Namespace::name.name) + as? String, + baseTranslationValue = baseTranslationValue, + baseLanguageId = baseLanguageId, + ) + } + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/CreateProjectGroupModelProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/CreateProjectGroupModelProvider.kt index 8c67441b66..12196f009f 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/CreateProjectGroupModelProvider.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createProject/CreateProjectGroupModelProvider.kt @@ -13,7 +13,7 @@ class CreateProjectGroupModelProvider( private val jooqContext: DSLContext, ) : GroupModelProvider { - override fun provideGroupModel(groupIds: List): Map { + override fun provideGroup(groupIds: List): Map { val query = jooqContext .select( @@ -63,7 +63,7 @@ class CreateProjectGroupModelProvider( }.toMap() } - override fun provideItemModel( + override fun provideItems( groupId: Long, pageable: Pageable, ): Page { diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupModel.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupModel.kt deleted file mode 100644 index 1e7855d5c8..0000000000 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupModel.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.tolgee.activity.groups.viewProviders.keyCreate - -class CreateKeyGroupModel( - val keyCount: Int, -) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupModelProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupModelProvider.kt deleted file mode 100644 index 79ecaa7635..0000000000 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/keyCreate/CreateKeyGroupModelProvider.kt +++ /dev/null @@ -1,78 +0,0 @@ -package io.tolgee.activity.groups.viewProviders.keyCreate - -import io.tolgee.activity.groups.ActivityGroupType -import io.tolgee.activity.groups.GroupModelProvider -import io.tolgee.activity.groups.dataProviders.DescriptionMapping -import io.tolgee.activity.groups.dataProviders.GroupDataProvider -import io.tolgee.model.key.Key -import io.tolgee.model.key.KeyMeta -import io.tolgee.model.translation.Translation -import org.springframework.data.domain.Page -import org.springframework.data.domain.Pageable -import org.springframework.stereotype.Component - -@Component -class CreateKeyGroupModelProvider( - private val groupDataProvider: GroupDataProvider, -) : - GroupModelProvider { - override fun provideGroupModel(groupIds: List): Map { - val keyCounts = - groupDataProvider.provideCounts(ActivityGroupType.CREATE_KEY, groupIds = groupIds, entityClass = Key::class) - - return groupIds.associateWith { - CreateKeyGroupModel( - keyCounts[it] ?: 0, - ) - } - } - - override fun provideItemModel( - groupId: Long, - pageable: Pageable, - ): Page { - val entities = - groupDataProvider.provideRelevantModifiedEntities( - ActivityGroupType.CREATE_KEY, - Key::class, - groupId, - pageable, - ) - - val entityIds = entities.map { it.entityId }.toList() - - val relatedEntities = - groupDataProvider.getRelatedEntities( - entities, - groupType = ActivityGroupType.CREATE_KEY, - groupId = groupId, - descriptionMapping = - listOf( - DescriptionMapping( - entityClass = KeyMeta::class, - field = "key", - entityIds = entityIds, - ), - DescriptionMapping( - entityClass = Translation::class, - field = "key", - entityIds = entityIds, - ), - ), - ) - - return entities.map { - CreateKeyGroupItemModel( - it.entityId, - name = it.getFieldFromView(Key::name.name), - tags = it.getFieldFromViewNullable("tags") ?: emptySet(), - description = it.getFieldFromViewNullable("description"), - custom = it.getFieldFromViewNullable("custom"), - isPlural = it.getFieldFromView("isPlural"), - pluralArgName = it.getFieldFromViewNullable("pluralArgName"), - namespace = null, - baseTranslationValue = null, - ) - } - } -} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/setTranslations/SetTranslationsGroupItemModel.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/setTranslations/SetTranslationsGroupItemModel.kt new file mode 100644 index 0000000000..a6a09de9b7 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/setTranslations/SetTranslationsGroupItemModel.kt @@ -0,0 +1,23 @@ +package io.tolgee.activity.groups.viewProviders.setTranslations + +import io.swagger.v3.oas.annotations.media.Schema +import io.tolgee.api.IKeyModel +import io.tolgee.sharedDocs.Key +import org.springframework.hateoas.server.core.Relation + +@Relation(collectionRelation = "items", itemRelation = "item") +class SetTranslationsGroupItemModel( + override val id: Long, + override val name: String, + override val namespace: String?, + @Schema(description = Key.IS_PLURAL_FIELD) + val isPlural: Boolean, + @Schema(description = Key.PLURAL_ARG_NAME_FIELD) + val pluralArgName: String?, + @Schema(description = "The base translation value entered when key was created") + val baseTranslationValue: String?, + val tags: List, + override val description: String?, + override val custom: Map?, + val baseLanguageId: Long?, +) : IKeyModel diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/setTranslations/SetTranslationsGroupModel.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/setTranslations/SetTranslationsGroupModel.kt new file mode 100644 index 0000000000..22eb2a4ec7 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/setTranslations/SetTranslationsGroupModel.kt @@ -0,0 +1,5 @@ +package io.tolgee.activity.groups.viewProviders.setTranslations + +class SetTranslationsGroupModel( + val translationCount: Int, +) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/setTranslations/SetTranslationsGroupModelProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/setTranslations/SetTranslationsGroupModelProvider.kt new file mode 100644 index 0000000000..5057f4841d --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/setTranslations/SetTranslationsGroupModelProvider.kt @@ -0,0 +1,37 @@ +package io.tolgee.activity.groups.viewProviders.setTranslations + +import io.tolgee.activity.groups.ActivityGroupType +import io.tolgee.activity.groups.GroupModelProvider +import io.tolgee.activity.groups.dataProviders.GroupDataProvider +import io.tolgee.model.translation.Translation +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.stereotype.Component + +@Component +class SetTranslationsGroupModelProvider( + private val groupDataProvider: GroupDataProvider, +) : + GroupModelProvider { + override fun provideGroup(groupIds: List): Map { + val translationCounts = + groupDataProvider.provideCounts( + ActivityGroupType.SET_TRANSLATIONS, + groupIds = groupIds, + entityClass = Translation::class, + ) + + return groupIds.associateWith { + SetTranslationsGroupModel( + translationCounts[it] ?: 0, + ) + } + } + + override fun provideItems( + groupId: Long, + pageable: Pageable, + ): Page { + return Page.empty() + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/iterceptor/InterceptedEventsManager.kt b/backend/data/src/main/kotlin/io/tolgee/activity/iterceptor/InterceptedEventsManager.kt index af9641caa5..bd3f0cb08b 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/iterceptor/InterceptedEventsManager.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/iterceptor/InterceptedEventsManager.kt @@ -281,7 +281,7 @@ class InterceptedEventsManager( revision.isInitializedByInterceptor = true revision.authorId = userAccount?.id try { - revision.projectId = projectHolder.project.id + revision.setProject(projectHolder.project) activityHolder.organizationId = projectHolder.project.organizationOwnerId } catch (e: ProjectNotSelectedException) { logger.debug("Project is not set in ProjectHolder. Activity will be stored without projectId.") diff --git a/backend/data/src/main/kotlin/io/tolgee/api/ProjectIdAndBaseLanguageId.kt b/backend/data/src/main/kotlin/io/tolgee/api/ProjectIdAndBaseLanguageId.kt new file mode 100644 index 0000000000..8d045c0095 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/api/ProjectIdAndBaseLanguageId.kt @@ -0,0 +1,6 @@ +package io.tolgee.api + +interface ProjectIdAndBaseLanguageId { + val id: Long + val baseLanguageId: Long? +} diff --git a/backend/data/src/main/kotlin/io/tolgee/batch/ChunkProcessingUtil.kt b/backend/data/src/main/kotlin/io/tolgee/batch/ChunkProcessingUtil.kt index 5346568876..6e3cbf96ac 100644 --- a/backend/data/src/main/kotlin/io/tolgee/batch/ChunkProcessingUtil.kt +++ b/backend/data/src/main/kotlin/io/tolgee/batch/ChunkProcessingUtil.kt @@ -10,6 +10,7 @@ import io.tolgee.exceptions.OutOfCreditsException import io.tolgee.model.batch.BatchJob import io.tolgee.model.batch.BatchJobChunkExecution import io.tolgee.model.batch.BatchJobChunkExecutionStatus +import io.tolgee.service.project.ProjectService import io.tolgee.util.Logging import io.tolgee.util.logger import jakarta.persistence.EntityManager @@ -53,7 +54,8 @@ open class ChunkProcessingUtil( val activityRevision = activityHolder.activityRevision activityRevision.batchJobChunkExecution = execution val batchJobDto = batchJobService.getJobDto(job.id) - activityRevision.projectId = batchJobDto.projectId + val project = projectService.get(batchJobDto.projectId) + activityRevision.setProject(project) activityHolder.activity = batchJobDto.type.activityType activityRevision.authorId = batchJobDto.authorId } @@ -150,6 +152,10 @@ open class ChunkProcessingUtil( batchJobService.getProcessor(job.type) } + private val projectService: ProjectService by lazy { + applicationContext.getBean(ProjectService::class.java) + } + private var successfulTargets: List? = null private val toProcess by lazy { diff --git a/backend/data/src/main/kotlin/io/tolgee/component/demoProject/DemoProjectCreator.kt b/backend/data/src/main/kotlin/io/tolgee/component/demoProject/DemoProjectCreator.kt index 6569eb2ca5..0beeab7666 100644 --- a/backend/data/src/main/kotlin/io/tolgee/component/demoProject/DemoProjectCreator.kt +++ b/backend/data/src/main/kotlin/io/tolgee/component/demoProject/DemoProjectCreator.kt @@ -39,7 +39,7 @@ class DemoProjectCreator( fun createDemoProject(): Project { activityHolder.activity = ActivityType.CREATE_PROJECT - activityHolder.activityRevision.projectId = project.id + activityHolder.activityRevision.setProject(project) setStates() addBigMeta() addScreenshots() diff --git a/backend/data/src/main/kotlin/io/tolgee/dtos/cacheable/ProjectDto.kt b/backend/data/src/main/kotlin/io/tolgee/dtos/cacheable/ProjectDto.kt index ae9d65fc26..78387e8362 100644 --- a/backend/data/src/main/kotlin/io/tolgee/dtos/cacheable/ProjectDto.kt +++ b/backend/data/src/main/kotlin/io/tolgee/dtos/cacheable/ProjectDto.kt @@ -1,6 +1,7 @@ package io.tolgee.dtos.cacheable import io.tolgee.api.ISimpleProject +import io.tolgee.api.ProjectIdAndBaseLanguageId import io.tolgee.model.Project import java.io.Serializable @@ -13,7 +14,8 @@ data class ProjectDto( var aiTranslatorPromptDescription: String?, override var avatarHash: String? = null, override var icuPlaceholders: Boolean, -) : Serializable, ISimpleProject { + override val baseLanguageId: Long?, +) : Serializable, ISimpleProject, ProjectIdAndBaseLanguageId { companion object { fun fromEntity(entity: Project) = ProjectDto( @@ -25,6 +27,7 @@ data class ProjectDto( aiTranslatorPromptDescription = entity.aiTranslatorPromptDescription, avatarHash = entity.avatarHash, icuPlaceholders = entity.icuPlaceholders, + baseLanguageId = entity.baseLanguageId, ) } } diff --git a/backend/data/src/main/kotlin/io/tolgee/model/Project.kt b/backend/data/src/main/kotlin/io/tolgee/model/Project.kt index a1f13cf757..cc9525b0af 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/Project.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/Project.kt @@ -3,6 +3,7 @@ package io.tolgee.model import io.tolgee.activity.annotation.ActivityLoggedEntity import io.tolgee.activity.annotation.ActivityLoggedProp import io.tolgee.api.ISimpleProject +import io.tolgee.api.ProjectIdAndBaseLanguageId import io.tolgee.exceptions.NotFoundException import io.tolgee.model.automations.Automation import io.tolgee.model.contentDelivery.ContentDeliveryConfig @@ -50,7 +51,7 @@ class Project( @field:Size(min = 3, max = 60) @field:Pattern(regexp = "^[a-z0-9-]*[a-z]+[a-z0-9-]*$", message = "invalid_pattern") override var slug: String? = null, -) : AuditModel(), ModelWithAvatar, EntityWithId, SoftDeletable, ISimpleProject { +) : AuditModel(), ModelWithAvatar, EntityWithId, SoftDeletable, ISimpleProject, ProjectIdAndBaseLanguageId { @OrderBy("id") @OneToMany(fetch = FetchType.LAZY, mappedBy = "project") var languages: MutableSet = LinkedHashSet() @@ -157,4 +158,7 @@ class Project( } } } + + override val baseLanguageId: Long? + get() = this.baseLanguage?.id } diff --git a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityDescribingEntity.kt b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityDescribingEntity.kt index f2d28ac8f0..194371d173 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityDescribingEntity.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityDescribingEntity.kt @@ -23,12 +23,16 @@ class ActivityDescribingEntity( val entityClass: String, @Id val entityId: Long, -) : Serializable { +) : Serializable, ActivityEntityWithDescription { @Column(columnDefinition = "jsonb") @Type(JsonBinaryType::class) var data: Map = mutableMapOf() @Type(JsonBinaryType::class) @Column(columnDefinition = "jsonb") - var describingRelations: Map? = null + override var describingRelations: Map? = null + + @Column(columnDefinition = "jsonb") + @Type(JsonBinaryType::class) + override var additionalDescription: MutableMap? = null } diff --git a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityEntityWithDescription.kt b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityEntityWithDescription.kt new file mode 100644 index 0000000000..a4e4c08817 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityEntityWithDescription.kt @@ -0,0 +1,20 @@ +package io.tolgee.model.activity + +import io.tolgee.activity.data.EntityDescriptionRef + +interface ActivityEntityWithDescription { + var describingRelations: Map? + + /** + * This field is filled by components implementing [io.tolgee.activity.ActivityAdditionalDescriber] + */ + var additionalDescription: MutableMap? + + fun initAdditionalDescription(): MutableMap { + return additionalDescription ?: let { + val value = mutableMapOf() + additionalDescription = value + value + } + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityGroup.kt b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityGroup.kt index f8f873b922..f65f165112 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityGroup.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityGroup.kt @@ -40,4 +40,6 @@ class ActivityGroup( @ManyToMany(mappedBy = "activityGroups") var activityRevisions: MutableList = mutableListOf() + + var matchingString: String? = null } diff --git a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityModifiedEntity.kt b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityModifiedEntity.kt index 3a580bb006..fa776a4503 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityModifiedEntity.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityModifiedEntity.kt @@ -33,7 +33,7 @@ class ActivityModifiedEntity( */ @Id val entityId: Long, -) : Serializable { +) : Serializable, ActivityEntityWithDescription { /** * Map of field to object containing old and new values */ @@ -54,7 +54,11 @@ class ActivityModifiedEntity( */ @Column(columnDefinition = "jsonb") @Type(JsonBinaryType::class) - var describingRelations: Map? = null + override var describingRelations: Map? = null + + @Column(columnDefinition = "jsonb") + @Type(JsonBinaryType::class) + override var additionalDescription: MutableMap? = null @Enumerated var revisionType: RevisionType = RevisionType.MOD diff --git a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityRevision.kt b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityRevision.kt index 1d470c935c..ec74a7b4f1 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityRevision.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityRevision.kt @@ -2,6 +2,7 @@ package io.tolgee.model.activity import io.hypersistence.utils.hibernate.type.json.JsonBinaryType import io.tolgee.activity.data.ActivityType +import io.tolgee.api.ProjectIdAndBaseLanguageId import io.tolgee.component.CurrentDateProvider import io.tolgee.model.batch.BatchJob import io.tolgee.model.batch.BatchJobChunkExecution @@ -111,6 +112,17 @@ class ActivityRevision : java.io.Serializable { @ManyToMany var activityGroups: MutableList = mutableListOf() + /** + * We need to store it to know which language was the base language when the change was made + * for group and filtering purposes + */ + var baseLanguageId: Long? = null + + fun setProject(project: ProjectIdAndBaseLanguageId) { + this.projectId = project.id + this.baseLanguageId = project.baseLanguageId + } + companion object { @Configurable class ActivityRevisionListener { diff --git a/backend/data/src/main/kotlin/io/tolgee/model/key/Key.kt b/backend/data/src/main/kotlin/io/tolgee/model/key/Key.kt index 7eeb3ace0b..8993764f97 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/key/Key.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/key/Key.kt @@ -64,10 +64,12 @@ class Key( var keyScreenshotReferences: MutableList = mutableListOf() @ActivityLoggedProp + @ActivityDescribingProp @ColumnDefault("false") var isPlural: Boolean = false @ActivityLoggedProp + @ActivityDescribingProp var pluralArgName: String? = null constructor( diff --git a/backend/data/src/main/kotlin/io/tolgee/repository/activity/ActivityGroupRepository.kt b/backend/data/src/main/kotlin/io/tolgee/repository/activity/ActivityGroupRepository.kt index 2990549609..ced07861c2 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/activity/ActivityGroupRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/activity/ActivityGroupRepository.kt @@ -13,6 +13,7 @@ interface ActivityGroupRepository : JpaRepository { SELECT ag.id, ag.type, + ag.matching_string, MAX(ar.timestamp) AS last_activity, MIN(ar.timestamp) AS first_activity FROM activity_group ag @@ -22,6 +23,7 @@ interface ActivityGroupRepository : JpaRepository { ag.project_id = :projectId AND ag.author_id = :authorId AND ag.type = :groupTypeName + AND (ag.matching_string = :matchingString or (:matchingString is null)) GROUP BY ag.id order by ag.id desc limit 1 @@ -31,5 +33,6 @@ interface ActivityGroupRepository : JpaRepository { groupTypeName: String, authorId: Long?, projectId: Long?, + matchingString: String?, ): List> } diff --git a/backend/data/src/main/kotlin/io/tolgee/service/language/LanguageService.kt b/backend/data/src/main/kotlin/io/tolgee/service/language/LanguageService.kt index ff5c7ffad9..f24b8b56f0 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/language/LanguageService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/language/LanguageService.kt @@ -101,7 +101,7 @@ class LanguageService( ) { activityHolder.activity = ActivityType.HARD_DELETE_LANGUAGE activityHolder.activityRevision.authorId = authorId - activityHolder.activityRevision.projectId = language.project.id + activityHolder.activityRevision.setProject(language.project) hardDeleteLanguage(language) } diff --git a/backend/data/src/main/kotlin/io/tolgee/service/project/ProjectService.kt b/backend/data/src/main/kotlin/io/tolgee/service/project/ProjectService.kt index 2db4e12201..0985cb6dca 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/project/ProjectService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/project/ProjectService.kt @@ -404,7 +404,7 @@ class ProjectService( projectRepository.save(project) if (isCreating) { projectHolder.project = ProjectDto.fromEntity(project) - activityHolder.activityRevision.projectId = projectHolder.project.id + activityHolder.activityRevision.setProject(project) } return project } diff --git a/backend/data/src/main/resources/db/changelog/schema.xml b/backend/data/src/main/resources/db/changelog/schema.xml index 3606005949..8509e4c786 100644 --- a/backend/data/src/main/resources/db/changelog/schema.xml +++ b/backend/data/src/main/resources/db/changelog/schema.xml @@ -3539,4 +3539,24 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/backend/security/src/main/kotlin/io/tolgee/security/authorization/ProjectAuthorizationInterceptor.kt b/backend/security/src/main/kotlin/io/tolgee/security/authorization/ProjectAuthorizationInterceptor.kt index 7757f21723..3857d13b76 100644 --- a/backend/security/src/main/kotlin/io/tolgee/security/authorization/ProjectAuthorizationInterceptor.kt +++ b/backend/security/src/main/kotlin/io/tolgee/security/authorization/ProjectAuthorizationInterceptor.kt @@ -139,7 +139,7 @@ class ProjectAuthorizationInterceptor( } projectHolder.project = project - activityHolder.activityRevision.projectId = project.id + activityHolder.activityRevision.setProject(project) organizationHolder.organization = organizationService.findDto(project.organizationOwnerId) ?: throw NotFoundException(Message.ORGANIZATION_NOT_FOUND) diff --git a/gradle/liquibase.gradle b/gradle/liquibase.gradle index e807bd8ef5..0c9283802e 100644 --- a/gradle/liquibase.gradle +++ b/gradle/liquibase.gradle @@ -35,9 +35,9 @@ ext { "billing_sequence," + "activity_sequence," + "FK9xs5a07fba5yqje5jqm6qrehs," + - "column:textsearchable_.*" + + "column:textsearchable_.*," + "column:enabled_features,"+ - "table:temp_*" + "table:temp_.*" } } } diff --git a/webapp/src/component/activity/groups/ActivityGroupItem.tsx b/webapp/src/component/activity/groups/ActivityGroupItem.tsx index 39448a6d54..fbae684cbb 100644 --- a/webapp/src/component/activity/groups/ActivityGroupItem.tsx +++ b/webapp/src/component/activity/groups/ActivityGroupItem.tsx @@ -3,6 +3,7 @@ import { components } from 'tg.service/apiSchema.generated'; import { CreateProjectActivityGroup } from './groupTypeComponents/CreateProjectActivityGroup'; import { CollapsibleActivityGroup } from './groupTypeComponents/CollapsibleActivityGroup'; import { CreateKeysActivityGroup } from './groupTypeComponents/CreateKeysActivityGroup'; +import { SetTranslationsActivityGroup } from './groupTypeComponents/SetTranslationsActivityGroup'; export const ActivityGroupItem: FC<{ item: components['schemas']['ActivityGroupModel']; @@ -12,6 +13,8 @@ export const ActivityGroupItem: FC<{ return ; case 'CREATE_KEY': return ; + case 'SET_TRANSLATIONS': + return ; default: return ( {props.item.type} diff --git a/webapp/src/component/activity/groups/SimpleTableExpandedContent.tsx b/webapp/src/component/activity/groups/SimpleTableExpandedContent.tsx new file mode 100644 index 0000000000..971bc50d02 --- /dev/null +++ b/webapp/src/component/activity/groups/SimpleTableExpandedContent.tsx @@ -0,0 +1,68 @@ +import React, { FC } from 'react'; +import { UseQueryResult } from 'react-query'; +import { PaginatedHateoasList } from '../../common/list/PaginatedHateoasList'; +import { + Table, + TableBody, + TableCell, + TableHead, + TableRow, +} from '@mui/material'; + +type Loadable = UseQueryResult<{ + _embedded?: { items?: Record[] }; +}>; +type SimpleTableExpandedContentProps = { + getData: (page: number) => Loadable; +}; + +export const SimpleTableExpandedContent: FC = ( + props +) => { + const [page, setPage] = React.useState(0); + + const loadable = props.getData(page); + + const fields = getFields(loadable); + + const Table: FC = (props) => { + return {props.children}; + }; + + return ( + ( + + {fields.map((f, idx) => ( + {i[f]} + ))} + + )} + onPageChange={(p) => setPage(p)} + loadable={loadable} + /> + ); +}; + +const TheTable: FC<{ headItems: string[] }> = (props) => { + return ( + + + {props.headItems.map((item, idx) => ( + {item} + ))} + + {props.children} +
+ ); +}; + +function getFields(loadable: Loadable) { + const fields = new Set(); + loadable.data?._embedded?.items?.forEach((i) => { + Object.keys(i).forEach((k) => fields.add(k)); + }); + + return [...fields]; +} diff --git a/webapp/src/component/activity/groups/groupTypeComponents/CreateKeysActivityGroup.tsx b/webapp/src/component/activity/groups/groupTypeComponents/CreateKeysActivityGroup.tsx index d1af8b4bfb..3aeee93c5d 100644 --- a/webapp/src/component/activity/groups/groupTypeComponents/CreateKeysActivityGroup.tsx +++ b/webapp/src/component/activity/groups/groupTypeComponents/CreateKeysActivityGroup.tsx @@ -3,15 +3,7 @@ import { components } from 'tg.service/apiSchema.generated'; import { CollapsibleActivityGroup } from './CollapsibleActivityGroup'; import { useApiQuery } from 'tg.service/http/useQueryApi'; import { useProject } from 'tg.hooks/useProject'; -import { PaginatedHateoasList } from '../../../common/list/PaginatedHateoasList'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableRow, -} from '@mui/material'; -import { T } from '@tolgee/react'; +import { SimpleTableExpandedContent } from '../SimpleTableExpandedContent'; type Group = components['schemas']['ActivityGroupCreateKeyModel']; @@ -29,41 +21,17 @@ export const CreateKeysActivityGroup: FC<{ const ExpandedContent: FC<{ group: Group }> = (props) => { const project = useProject(); - - const [page, setPage] = React.useState(0); - - const loadable = useApiQuery({ - url: '/v2/projects/{projectId}/activity/group-items/create-key/{groupId}', - method: 'get', - path: { projectId: project.id, groupId: props.group.id }, - query: { - page: page, - size: 20, - }, - }); - return ( - ( - - {i.name} - - )} - onPageChange={(p) => setPage(p)} - loadable={loadable} - /> - ); -}; - -const TheTable: FC = (props) => { + const getData = (page: number) => + useApiQuery({ + url: '/v2/projects/{projectId}/activity/group-items/create-key/{groupId}', + method: 'get', + path: { projectId: project.id, groupId: props.group.id }, + query: { + page: page, + size: 20, + }, + }); return ( - - - - - - - {props.children} -
+ ); }; diff --git a/webapp/src/component/activity/groups/groupTypeComponents/SetTranslationsActivityGroup.tsx b/webapp/src/component/activity/groups/groupTypeComponents/SetTranslationsActivityGroup.tsx new file mode 100644 index 0000000000..568db378b3 --- /dev/null +++ b/webapp/src/component/activity/groups/groupTypeComponents/SetTranslationsActivityGroup.tsx @@ -0,0 +1,35 @@ +import React, { FC } from 'react'; +import { components } from 'tg.service/apiSchema.generated'; +import { CollapsibleActivityGroup } from './CollapsibleActivityGroup'; + +type Group = components['schemas']['ActivityGroupSetTranslationsModel']; + +export const SetTranslationsActivityGroup: FC<{ + group: Group; +}> = ({ group }) => { + return ( + } + > + {group.author?.name} Translated {group.data?.translationCount} strings{' '} + + ); +}; + +const ExpandedContent: FC<{ group: Group }> = (props) => { + // const project = useProject(); + // const getData = (page: number) => + // useApiQuery({ + // url: '/v2/projects/{projectId}/activity/group-items/create-key/{groupId}', + // method: 'get', + // path: { projectId: project.id, groupId: props.group.id }, + // query: { + // page: page, + // size: 20, + // }, + // }); + // return ( + // + // ); + return null; +}; diff --git a/webapp/src/service/apiSchema.generated.ts b/webapp/src/service/apiSchema.generated.ts index f0ec151570..869060a177 100644 --- a/webapp/src/service/apiSchema.generated.ts +++ b/webapp/src/service/apiSchema.generated.ts @@ -1179,24 +1179,6 @@ export interface components { | "SERVER_ADMIN"; /** @description The user's permission type. This field is null if uses granular permissions */ type?: "NONE" | "VIEW" | "TRANSLATE" | "REVIEW" | "EDIT" | "MANAGE"; - /** - * @description List of languages user can translate to. If null, all languages editing is permitted. - * @example 200001,200004 - */ - translateLanguageIds?: number[]; - /** - * @description List of languages user can change state to. If null, changing state of all language values is permitted. - * @example 200001,200004 - */ - stateChangeLanguageIds?: number[]; - /** - * @deprecated - * @description Deprecated (use translateLanguageIds). - * - * List of languages current user has TRANSLATE permission to. If null, all languages edition is permitted. - * @example 200001,200004 - */ - permittedLanguageIds?: number[]; /** * @description Granted scopes to the user. When user has type permissions, this field contains permission scopes of the type. * @example KEYS_EDIT,TRANSLATIONS_VIEW @@ -1234,6 +1216,24 @@ export interface components { * @example 200001,200004 */ viewLanguageIds?: number[]; + /** + * @description List of languages user can translate to. If null, all languages editing is permitted. + * @example 200001,200004 + */ + translateLanguageIds?: number[]; + /** + * @description List of languages user can change state to. If null, changing state of all language values is permitted. + * @example 200001,200004 + */ + stateChangeLanguageIds?: number[]; + /** + * @deprecated + * @description Deprecated (use translateLanguageIds). + * + * List of languages current user has TRANSLATE permission to. If null, all languages edition is permitted. + * @example 200001,200004 + */ + permittedLanguageIds?: number[]; }; LanguageModel: { /** Format: int64 */ @@ -2200,15 +2200,15 @@ export interface components { token: string; /** Format: int64 */ id: number; - description: string; - /** Format: int64 */ - expiresAt?: number; - /** Format: int64 */ - lastUsedAt?: number; /** Format: int64 */ createdAt: number; /** Format: int64 */ updatedAt: number; + /** Format: int64 */ + expiresAt?: number; + /** Format: int64 */ + lastUsedAt?: number; + description: string; }; SetOrganizationRoleDto: { roleType: "MEMBER" | "OWNER"; @@ -2364,14 +2364,14 @@ export interface components { /** Format: int64 */ id: number; username?: string; - description: string; scopes: string[]; /** Format: int64 */ expiresAt?: number; /** Format: int64 */ - lastUsedAt?: number; - /** Format: int64 */ projectId: number; + /** Format: int64 */ + lastUsedAt?: number; + description: string; projectName: string; userFullName?: string; }; @@ -3530,18 +3530,18 @@ export interface components { name: string; /** Format: int64 */ id: number; - /** @example This is a beautiful organization full of beautiful and clever people */ - description?: string; avatar?: components["schemas"]["Avatar"]; /** @example btforg */ slug: string; + /** @example This is a beautiful organization full of beautiful and clever people */ + description?: string; + basePermissions: components["schemas"]["PermissionModel"]; /** * @description The role of currently authorized user. * * Can be null when user has direct access to one of the projects owned by the organization. */ currentUserRole?: "MEMBER" | "OWNER"; - basePermissions: components["schemas"]["PermissionModel"]; }; PublicBillingConfigurationDTO: { enabled: boolean; @@ -3678,9 +3678,9 @@ export interface components { name: string; /** Format: int64 */ id: number; - namespace?: string; - description?: string; translation?: string; + description?: string; + namespace?: string; baseTranslation?: string; }; KeySearchSearchResultModel: { @@ -3688,9 +3688,9 @@ export interface components { name: string; /** Format: int64 */ id: number; - namespace?: string; - description?: string; translation?: string; + description?: string; + namespace?: string; baseTranslation?: string; }; PagedModelKeySearchSearchResultModel: { @@ -4527,6 +4527,15 @@ export interface components { author?: components["schemas"]["SimpleUserAccountModel"]; mentionedLanguageIds: number[]; } + | { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "SET_BASE_TRANSLATION"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + } | { /** Format: int64 */ id: number; @@ -4534,6 +4543,10 @@ export interface components { timestamp: number; type: "SET_TRANSLATIONS"; author?: components["schemas"]["SimpleUserAccountModel"]; + data?: { + /** Format: int32 */ + translationCount: number; + }; mentionedLanguageIds: number[]; } | { @@ -4889,6 +4902,8 @@ export interface components { description?: string; /** @description Custom values of the key */ custom?: { [key: string]: { [key: string]: unknown } }; + /** Format: int64 */ + baseLanguageId?: number; }; PagedModelCreateKeyGroupItemModel: { _embedded?: { @@ -5306,15 +5321,15 @@ export interface components { user: components["schemas"]["SimpleUserAccountModel"]; /** Format: int64 */ id: number; - description: string; - /** Format: int64 */ - expiresAt?: number; - /** Format: int64 */ - lastUsedAt?: number; /** Format: int64 */ createdAt: number; /** Format: int64 */ updatedAt: number; + /** Format: int64 */ + expiresAt?: number; + /** Format: int64 */ + lastUsedAt?: number; + description: string; }; PagedModelOrganizationModel: { _embedded?: { @@ -5482,14 +5497,14 @@ export interface components { /** Format: int64 */ id: number; username?: string; - description: string; scopes: string[]; /** Format: int64 */ expiresAt?: number; /** Format: int64 */ - lastUsedAt?: number; - /** Format: int64 */ projectId: number; + /** Format: int64 */ + lastUsedAt?: number; + description: string; projectName: string; userFullName?: string; }; @@ -5531,6 +5546,7 @@ export interface components { type: | "SET_TRANSLATION_STATE" | "REVIEW" + | "SET_BASE_TRANSLATION" | "SET_TRANSLATIONS" | "DISMISS_AUTO_TRANSLATED_STATE" | "SET_OUTDATED_FLAG" @@ -5573,6 +5589,7 @@ export interface components { /** Format: int64 */ projectId?: number; activityRevisions: components["schemas"]["ActivityRevision"][]; + matchingString?: string; }; ActivityModifiedEntity: { activityRevision: components["schemas"]["ActivityRevision"]; @@ -5648,6 +5665,9 @@ export interface components { batchJobChunkExecution?: components["schemas"]["BatchJobChunkExecution"]; batchJob?: components["schemas"]["BatchJob"]; activityGroups: components["schemas"]["ActivityGroup"][]; + /** Format: int64 */ + baseLanguageId?: number; + project?: components["schemas"]["ProjectIdAndBaseLanguageId"]; isInitializedByInterceptor: boolean; /** Format: int32 */ cancelledBatchJobExecutionCount?: number; @@ -6755,10 +6775,6 @@ export interface components { viewLanguages: components["schemas"]["Language"][]; stateChangeLanguages: components["schemas"]["Language"][]; project?: components["schemas"]["Project"]; - translateLanguageIds?: number[]; - stateChangeLanguageIds?: number[]; - /** Format: int64 */ - userId?: number; scopes: ( | "translations.view" | "translations.edit" @@ -6787,14 +6803,18 @@ export interface components { | "content-delivery.publish" | "webhooks.manage" )[]; - granular: boolean; /** Format: int64 */ projectId?: number; - viewLanguageIds?: number[]; + granular: boolean; /** Format: int64 */ - organizationId?: number; + userId?: number; /** Format: int64 */ invitationId?: number; + viewLanguageIds?: number[]; + /** Format: int64 */ + organizationId?: number; + translateLanguageIds?: number[]; + stateChangeLanguageIds?: number[]; }; Project: { /** Format: int64 */ @@ -6828,8 +6848,16 @@ export interface components { icuPlaceholders: boolean; /** Format: date-time */ deletedAt?: string; + /** Format: int64 */ + baseLanguageId?: number; disableActivityLogging: boolean; }; + ProjectIdAndBaseLanguageId: { + /** Format: int64 */ + id: number; + /** Format: int64 */ + baseLanguageId?: number; + }; S3ContentStorageConfig: { contentStorage: components["schemas"]["ContentStorage"]; bucketName: string; @@ -6874,8 +6902,8 @@ export interface components { height: number; hash: string; filename: string; - thumbnailFilename: string; pathWithSlash: string; + thumbnailFilename: string; disableActivityLogging: boolean; }; SlackConfig: { @@ -7010,11 +7038,11 @@ export interface components { slackConfig: components["schemas"]["SlackConfig"][]; userNotifications: components["schemas"]["UserNotification"][]; projectNotificationPreferences: components["schemas"]["NotificationPreferences"][]; - globalNotificationPreferences?: components["schemas"]["NotificationPreferences"]; + mfaEnabled?: boolean; deletable?: boolean; deleted: boolean; - mfaEnabled?: boolean; needsSuperJwt?: boolean; + globalNotificationPreferences?: components["schemas"]["NotificationPreferences"]; }; UserNotification: { type: @@ -7770,6 +7798,10 @@ export interface components { counts?: { [key: string]: number }; params?: { [key: string]: unknown }; }; + SetTranslationsGroupModel: { + /** Format: int32 */ + translationCount: number; + }; CreateKeyGroupModel: { /** Format: int32 */ keyCount: number; @@ -7807,6 +7839,15 @@ export interface components { author?: components["schemas"]["SimpleUserAccountModel"]; mentionedLanguageIds: number[]; }; + ActivityGroupSetBaseTranslationModel: { + /** Format: int64 */ + id: number; + /** Format: int64 */ + timestamp: number; + type: "SET_BASE_TRANSLATION"; + author?: components["schemas"]["SimpleUserAccountModel"]; + mentionedLanguageIds: number[]; + }; ActivityGroupSetTranslationsModel: { /** Format: int64 */ id: number; @@ -7814,6 +7855,10 @@ export interface components { timestamp: number; type: "SET_TRANSLATIONS"; author?: components["schemas"]["SimpleUserAccountModel"]; + data?: { + /** Format: int32 */ + translationCount: number; + }; mentionedLanguageIds: number[]; }; ActivityGroupDismissAutoTranslatedStateModel: { @@ -18625,6 +18670,7 @@ export interface operations { filterType?: | "SET_TRANSLATION_STATE" | "REVIEW" + | "SET_BASE_TRANSLATION" | "SET_TRANSLATIONS" | "DISMISS_AUTO_TRANSLATED_STATE" | "SET_OUTDATED_FLAG" From 8a77db4554f336e4478ba0ed15ad09810ffcb002 Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Tue, 26 Nov 2024 17:05:00 +0100 Subject: [PATCH 44/44] feat: Activity grouping --- .../activity/data/PropertyModification.kt | 6 ++-- .../ActivityKeyGroupModelAssembler.kt | 18 ++++++++++ .../GroupModelAssembler.kt | 7 ++++ .../baseModels/ActivityGroupKeyModel.kt | 8 +++++ .../groups/data/ActivityEntityView.kt | 33 +++++++++++++++++++ .../groups/data/DescribingEntityView.kt | 17 +++++++--- .../groups/data/ModifiedEntityView.kt | 13 ++------ .../createKey/CreateKeyGroupItemModel.kt | 2 +- .../createKey/CreateKeyGroupModelProvider.kt | 6 ++-- .../SetTranslationsGroupItemModel.kt | 23 ++++--------- 10 files changed, 95 insertions(+), 38 deletions(-) create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/baseModelAssemblers/ActivityKeyGroupModelAssembler.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/baseModelAssemblers/GroupModelAssembler.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/baseModels/ActivityGroupKeyModel.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/data/ActivityEntityView.kt diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/data/PropertyModification.kt b/backend/data/src/main/kotlin/io/tolgee/activity/data/PropertyModification.kt index 8cb7111ee6..b9d29cdeea 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/data/PropertyModification.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/data/PropertyModification.kt @@ -1,6 +1,6 @@ package io.tolgee.activity.data -data class PropertyModification( - val old: Any?, - val new: Any?, +data class PropertyModification( + val old: T?, + val new: T?, ) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/baseModelAssemblers/ActivityKeyGroupModelAssembler.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/baseModelAssemblers/ActivityKeyGroupModelAssembler.kt new file mode 100644 index 0000000000..0bcb680ca9 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/baseModelAssemblers/ActivityKeyGroupModelAssembler.kt @@ -0,0 +1,18 @@ +package io.tolgee.activity.groups.baseModelAssemblers + +import io.tolgee.activity.groups.baseModels.ActivityGroupKeyModel +import io.tolgee.activity.groups.data.ActivityEntityView +import io.tolgee.activity.groups.data.getAdditionalDescriptionFieldNullable +import io.tolgee.activity.groups.data.getFieldFromView +import io.tolgee.model.key.Key + +class ActivityKeyGroupModelAssembler : GroupModelAssembler { + override fun toModel(entity: ActivityEntityView): ActivityGroupKeyModel { + return ActivityGroupKeyModel( + id = entity.entityId, + name = entity.getFieldFromView(Key::name.name), + namespace = null, + baseTranslationText = entity.getAdditionalDescriptionFieldNullable("baseTranslation", "text"), + ) + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/baseModelAssemblers/GroupModelAssembler.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/baseModelAssemblers/GroupModelAssembler.kt new file mode 100644 index 0000000000..686d19fbab --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/baseModelAssemblers/GroupModelAssembler.kt @@ -0,0 +1,7 @@ +package io.tolgee.activity.groups.baseModelAssemblers + +import io.tolgee.activity.groups.data.ActivityEntityView + +interface GroupModelAssembler { + fun toModel(entity: ActivityEntityView): T +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/baseModels/ActivityGroupKeyModel.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/baseModels/ActivityGroupKeyModel.kt new file mode 100644 index 0000000000..ebcb0af830 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/baseModels/ActivityGroupKeyModel.kt @@ -0,0 +1,8 @@ +package io.tolgee.activity.groups.baseModels + +class ActivityGroupKeyModel( + val id: Long, + val name: String, + val namespace: String?, + val baseTranslationText: String?, +) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/ActivityEntityView.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/ActivityEntityView.kt new file mode 100644 index 0000000000..41459974fe --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/ActivityEntityView.kt @@ -0,0 +1,33 @@ +package io.tolgee.activity.groups.data + +interface ActivityEntityView { + val activityRevisionId: Long + val entityId: Long + val entityClass: String + val additionalDescription: Map? +} + +inline fun ActivityEntityView.getFieldFromViewNullable(name: String): T? { + return when (this) { + is DescribingEntityView -> + this.data[name] as? T + + is ModifiedEntityView -> + this.describingData[name] as? T ?: this.modifications[name]?.let { it.new as? T } + + else -> throw IllegalArgumentException("Unknown entity view type") + } +} + +inline fun ActivityEntityView.getFieldFromView(name: String): T { + return this.getFieldFromViewNullable(name) + ?: throw IllegalArgumentException("Field $name not found in describing data") +} + +inline fun ActivityEntityView.getAdditionalDescriptionFieldNullable( + fieldName: String, + propertyName: String, +): T? { + val field = this.additionalDescription?.get(fieldName) as? Map + return field?.get(propertyName) as? T +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/DescribingEntityView.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/DescribingEntityView.kt index 69c1ac816d..283828139c 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/DescribingEntityView.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/DescribingEntityView.kt @@ -3,9 +3,18 @@ package io.tolgee.activity.groups.data import io.tolgee.activity.data.EntityDescriptionRef class DescribingEntityView( - val entityId: Long, - val entityClass: String, + override val entityId: Long, + override val entityClass: String, val data: Map, val describingRelations: Map, - val activityRevisionId: Long, -) + override val activityRevisionId: Long, +) : ActivityEntityView { + inline fun getFieldFromViewNullable(name: String): T? { + return this.data[name] as? T + } + + inline fun getFieldFromView(name: String): T { + return this.data[name] as? T + ?: throw IllegalArgumentException("Field $name not found in describing data") + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/ModifiedEntityView.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/ModifiedEntityView.kt index 6eb262f640..6c0f7dd7cc 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/ModifiedEntityView.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/data/ModifiedEntityView.kt @@ -8,15 +8,6 @@ class ModifiedEntityView( val entityClass: String, val describingData: Map, val describingRelations: Map, - val modifications: Map, + val modifications: Map>, val activityRevisionId: Long, -) { - inline fun getFieldFromViewNullable(name: String): T? { - return this.describingData[name] as? T ?: this.modifications[name]?.let { it.new as? T } - } - - inline fun getFieldFromView(name: String): T { - return this.describingData[name] as? T ?: this.modifications[name]?.let { it.new as? T } - ?: throw IllegalArgumentException("Field $name not found in modifications or describing data") - } -} +) : ActivityEntityView diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createKey/CreateKeyGroupItemModel.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createKey/CreateKeyGroupItemModel.kt index d7d426c8bd..39243287c7 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createKey/CreateKeyGroupItemModel.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createKey/CreateKeyGroupItemModel.kt @@ -15,7 +15,7 @@ class CreateKeyGroupItemModel( @Schema(description = Key.PLURAL_ARG_NAME_FIELD) val pluralArgName: String?, @Schema(description = "The base translation value entered when key was created") - val baseTranslationValue: String?, + val baseTranslationText: String?, val tags: List, override val description: String?, override val custom: Map?, diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createKey/CreateKeyGroupModelProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createKey/CreateKeyGroupModelProvider.kt index da9c4264bb..0ffd861872 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createKey/CreateKeyGroupModelProvider.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/createKey/CreateKeyGroupModelProvider.kt @@ -4,6 +4,8 @@ import io.tolgee.activity.groups.ActivityGroupType import io.tolgee.activity.groups.GroupModelProvider import io.tolgee.activity.groups.data.DescribingMapping import io.tolgee.activity.groups.data.RelatedMapping +import io.tolgee.activity.groups.data.getFieldFromView +import io.tolgee.activity.groups.data.getFieldFromViewNullable import io.tolgee.activity.groups.dataProviders.GroupDataProvider import io.tolgee.model.key.Key import io.tolgee.model.key.KeyMeta @@ -77,7 +79,7 @@ class CreateKeyGroupModelProvider( relatedEntities[entity] ?.get(translationMapping)?.singleOrNull() - val baseTranslationValue = + val baseTranslationText = baseTranslation?.modifications ?.get("text") ?.new as? String @@ -103,7 +105,7 @@ class CreateKeyGroupModelProvider( ?.data ?.get(Namespace::name.name) as? String, - baseTranslationValue = baseTranslationValue, + baseTranslationText = baseTranslationText, baseLanguageId = baseLanguageId, ) } diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/setTranslations/SetTranslationsGroupItemModel.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/setTranslations/SetTranslationsGroupItemModel.kt index a6a09de9b7..806e82e1db 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/setTranslations/SetTranslationsGroupItemModel.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/setTranslations/SetTranslationsGroupItemModel.kt @@ -1,23 +1,12 @@ package io.tolgee.activity.groups.viewProviders.setTranslations -import io.swagger.v3.oas.annotations.media.Schema -import io.tolgee.api.IKeyModel -import io.tolgee.sharedDocs.Key +import io.tolgee.activity.data.PropertyModification +import io.tolgee.activity.groups.baseModels.ActivityGroupKeyModel import org.springframework.hateoas.server.core.Relation @Relation(collectionRelation = "items", itemRelation = "item") class SetTranslationsGroupItemModel( - override val id: Long, - override val name: String, - override val namespace: String?, - @Schema(description = Key.IS_PLURAL_FIELD) - val isPlural: Boolean, - @Schema(description = Key.PLURAL_ARG_NAME_FIELD) - val pluralArgName: String?, - @Schema(description = "The base translation value entered when key was created") - val baseTranslationValue: String?, - val tags: List, - override val description: String?, - override val custom: Map?, - val baseLanguageId: Long?, -) : IKeyModel + val id: Long, + val text: PropertyModification, + val key: ActivityGroupKeyModel, +)