From bc0f83c3214e7ad91011895f288cc3cb9acade92 Mon Sep 17 00:00:00 2001 From: Cynthia Date: Tue, 14 Nov 2023 11:10:08 +0100 Subject: [PATCH 01/57] 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 be842e981e3..9dbeb92cc1f 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 dccc52c8f41..003022a7b12 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 00000000000..5e47be121b7 --- /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 00000000000..f2592b453e9 --- /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 00000000000..967c4a5b0a6 --- /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 00000000000..be39437a194 --- /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 00000000000..e16dd11ac5b --- /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 00000000000..b28cda809d8 --- /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/57] 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 537f72ce055..5f741e65f5e 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 b3d4b1815a1..f7c18e8490b 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 516d1a2ae78..f97bd50c87d 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 f73554f8664..00000000000 --- 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 00000000000..b12f8a04430 --- /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 ec309c0fb63..00000000000 --- 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/57] 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 780713c1b57..a409ecb6f11 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 00000000000..94f5395dade --- /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 9c8e7e18d42..1393577a871 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 a2c9e881447..216d8077fac 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 5e47be121b7..096145acb33 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 7e0aa3cacd9..e8c15f965e7 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 00000000000..fce02785b03 --- /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 967c4a5b0a6..93783702b88 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 00000000000..57d4ea4395d --- /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 00000000000..a988d97d628 --- /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 00000000000..968bf0e2fb8 --- /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 f2592b453e9..041bcf59883 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 be39437a194..eb8833f5c2e 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 e16dd11ac5b..c099547b02e 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 fe29e2c1f4d..e371c312ae7 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 b28cda809d8..e7f58963b57 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 a2524c7207c..c9b794d942c 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 51e78ca6dd9..77517a796b3 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 645dc5269d1..98162d9354d 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 337eac3260b..e28fadd53a7 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 372e920ee6f..6c4de7192b3 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 00000000000..ac3f556a492 --- /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/57] 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 9dbeb92cc1f..8152e3db613 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 f97bd50c87d..1ac65e1b3f0 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 096145acb33..4822a1297f6 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 fce02785b03..d063c760a32 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 93783702b88..885d8ba8d4c 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 57d4ea4395d..17387d4a76a 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 a988d97d628..80323ac839d 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 c099547b02e..796e912a9ca 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 c9b794d942c..587274ff0d6 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/57] 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 1393577a871..f850fc62753 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 4822a1297f6..46528006094 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 a21d1b6eb31..89472b77b64 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 85dcf21cdb4..6bc8c0df6cf 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 d063c760a32..798980fb49f 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 885d8ba8d4c..08ef06bd89c 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 17387d4a76a..c5fba2b8c4f 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 80323ac839d..45ec691fe81 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 00000000000..faebba87cb9 --- /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 968bf0e2fb8..c7fa2a73636 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 eb8833f5c2e..5a43db091ff 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 796e912a9ca..a33a730c0f2 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 e371c312ae7..9a270e2beae 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 e7f58963b57..938f1970635 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 587274ff0d6..2da39c4572c 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 77517a796b3..e1f2f518222 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 e28fadd53a7..b6340d34648 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 6c4de7192b3..7eb77283375 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/57] 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 00000000000..b7915af5167 --- /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 94f5395dade..b1cb8d36fe5 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 c5fba2b8c4f..f8510ee2b0f 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 9a270e2beae..ed7c05ff6f2 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 938f1970635..fc730d332b7 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 e1f2f518222..6f39e7c1562 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 7eb77283375..5d9bc7dc8c1 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/57] 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 00000000000..f06d1adfeb6 --- /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 b7915af5167..b770e64aab7 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 b1cb8d36fe5..64adfbfcfe0 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 08ef06bd89c..70b03ea6508 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 f8510ee2b0f..84643b87d51 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 45ec691fe81..bec17283685 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 ed7c05ff6f2..8a0f7aa6fbc 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 6f39e7c1562..10234567bc6 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 cc5e136ffad..351f59e8f9a 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/57] 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 14e67ae6fcf..b8f5032513f 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 f06d1adfeb6..7f0187d028a 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 b770e64aab7..00000000000 --- 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 00000000000..d183c1738ba --- /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 00000000000..f8cefd8f101 --- /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 00000000000..3e6e391b18d --- /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 64adfbfcfe0..8848ff0d577 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 81c6fda2699..878fdaed7bf 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 005d68df7e2..02438216f3f 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 6bc8c0df6cf..e75b0f6a342 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 46528006094..c03748e7ba9 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 0e08d0a9ed7..06b94dfb77d 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 798980fb49f..741904fab46 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 70b03ea6508..00000000000 --- 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 00000000000..a06ef0245e1 --- /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 00000000000..6d1b3c27c61 --- /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 00000000000..0f162131047 --- /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 84643b87d51..d13f2575048 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 bec17283685..da5b898dcb6 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 faebba87cb9..e97299f3db4 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 c7fa2a73636..4550ada6fc3 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 041bcf59883..d1052e802e2 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 5a43db091ff..52af0a7e300 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 a33a730c0f2..b274e733768 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 fc730d332b7..00000000000 --- 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 2da39c4572c..a8c8ee7b5a3 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 00000000000..32101144394 --- /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 98162d9354d..514a0ea5cce 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 b6340d34648..a1ab0bb51a3 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 97180678d94..2de2f6ceb7c 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 39c82b6c299..eb6963b15ab 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/57] 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 25f1af2680e..367f3226820 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 3d98f154ad0..94e134fcb10 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 9e79354bc35..e807c86f60d 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 3d305f1906f..38f0c3d835e 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 8a2e0e50785..7e82b1811ff 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 c10c2154d3a..d41a89926f3 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 69e068c4fbf..6a2aa307d2d 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 b0dce3b9e6c..fcca30f56a3 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 6aee2a922ea..f08a0f58693 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 f13b2f04c58..9c74679aa26 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 eba534a3674..c5f5f6b1862 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 f56386dcedb..8a267595079 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 5081f578dd3..93ac9d39212 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 1176af09986..7ede747adc4 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 9c826e7ac60..af831c76be7 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 8e85e4cf724..8f21f49655c 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 eb6963b15ab..0c88300a8d6 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 00000000000..a39ab32b907 --- /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 bc0c663417b..754b69525d6 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/57] 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 7f0187d028a..52ca7d38de8 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 d183c1738ba..5cf19713e93 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 00000000000..e55756babd6 --- /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 a06ef0245e1..1b13671bce7 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 6d1b3c27c61..1bddd262ce6 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 52af0a7e300..5d7f17bf3af 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 32101144394..0c634ff7da6 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/57] 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 00000000000..856ad766f6f --- /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 02438216f3f..d4b6233038d 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 e75b0f6a342..652ae653d6f 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 c03748e7ba9..6d93beb777a 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 741904fab46..cf7eef61299 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 00000000000..50ee657789c --- /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 0f162131047..7a19dc2e017 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 d13f2575048..103ed5dcc14 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 00000000000..30c33c2015e --- /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 a8c8ee7b5a3..7abe7e58786 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 0c634ff7da6..098862e2c16 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 72390877096..818cd137280 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 514a0ea5cce..8984f0ed865 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 a1ab0bb51a3..51b063d6193 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 2de2f6ceb7c..4785e5263bf 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/57] 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 52ca7d38de8..1eb68e4c121 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 5cf19713e93..b00b503e18d 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 f8cefd8f101..4f85e248467 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 3e6e391b18d..506e49c30a2 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 00000000000..669ecdcf6fe --- /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 e55756babd6..85e133137c2 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 dfe1952f601..e512c691aac 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 00000000000..a1146d581db --- /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 ebf87e7aef7..1da12f11f1d 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 00000000000..88e057ea6b5 --- /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 652ae653d6f..cefde3bbe08 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 856ad766f6f..87054b17fa2 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 6d93beb777a..f5614b148f3 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 cf7eef61299..d326fd53665 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 50ee657789c..27144a35f1d 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 1bddd262ce6..5bf60d2087d 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 7a19dc2e017..49c8a40a8a0 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 103ed5dcc14..551d882b5ea 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 da5b898dcb6..a5f6bbaed37 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 d1052e802e2..2e416245ade 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 7abe7e58786..4b2d203902a 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 30c33c2015e..536131c07dc 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 098862e2c16..f702973c4e7 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 51b063d6193..059d13f5298 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 4785e5263bf..00113a279f7 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 a39ab32b907..a56414eb6bc 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/57] 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 d4c0efacc28..26f6b7aa159 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 0c88300a8d6..7d379693740 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/57] 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 e8c15f965e7..7e0aa3cacd9 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 cefde3bbe08..40be16d3792 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 551d882b5ea..8ddd86a1176 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 00113a279f7..ed491cc1a58 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/57] 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 7d379693740..ed74c25a9ad 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/57] 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 4f306a9ae11..3d03370a2bc 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 4f85e248467..16142f28ea2 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 482bc360dc6..f52482a3630 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 8a1ae27a1a0..04b9a9551f5 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 7d16b440017..7d15829fb0c 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 d6cdfa59e01..5512e3e367d 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 b427f0197c1..a75411b3610 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 7e0aa3cacd9..2dea105f5b8 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 d4b6233038d..9cf9dc8ab08 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 f77c497ae8b..cb71a6ce6aa 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 40be16d3792..67b0d6b541f 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 07b8471199f..336f3f5d471 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 166af57d49d..e18d8f0c981 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 06b94dfb77d..1fcf38c023c 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 924c3d03e48..7b026638198 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 2f121cfb248..83ce9edb2af 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 87054b17fa2..6da765f939b 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 f5614b148f3..5f8c2832c29 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 f702973c4e7..2583b1c05f9 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/57] 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 3d03370a2bc..4f306a9ae11 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/57] 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 f52482a3630..80865913ee1 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 04b9a9551f5..48da7d3b67e 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 7d15829fb0c..7d16b440017 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 5512e3e367d..d6cdfa59e01 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 a75411b3610..e10e678b41e 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 2dea105f5b8..7e0aa3cacd9 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 9cf9dc8ab08..8ab3643859c 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 cb71a6ce6aa..f77c497ae8b 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 67b0d6b541f..40be16d3792 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 336f3f5d471..07b8471199f 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 e18d8f0c981..166af57d49d 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 1fcf38c023c..06b94dfb77d 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 7b026638198..924c3d03e48 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 83ce9edb2af..0852804ed81 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 6da765f939b..87054b17fa2 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 5f8c2832c29..f5614b148f3 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 5d7f17bf3af..a78fc1f5f50 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 8a0f7aa6fbc..08f0ba2aa7f 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 10234567bc6..1ae27260879 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/57] 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 ff63ea7e081..444dbfce803 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 00000000000..0aa3c3ec354 --- /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 00000000000..e9182da6e11 --- /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 1538cfa4073..a209273ae2e 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 00000000000..141050165e9 --- /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 00000000000..67e8013471e --- /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 8e5bdb2b946..ae029e6a1bd 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 6d8bd31c2dc..8ec10a37b6a 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 721d75e4df1..36f23f6a1da 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 00000000000..e4d04e92f5a --- /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 1b31a1d57f9..5825b0e90af 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 24a58e7f30b..1601ea8813d 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 c75dd93cf9e..a96edc349a8 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 f5614b148f3..c81ddf93d96 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 00000000000..b04287a8dff --- /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 27144a35f1d..cdf2db5d571 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 00000000000..157c985e658 --- /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 49c8a40a8a0..51ebf35efb4 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 a5f6bbaed37..0ac6a6e4db5 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 00000000000..7698de36ad3 --- /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 2e416245ade..980aeec1b55 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 536131c07dc..8ba4e98896f 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 2583b1c05f9..80b837a1aab 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/57] 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 e9182da6e11..aecac369c9b 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 85e133137c2..936f458510e 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 e512c691aac..6c7ac282a77 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 51ebf35efb4..5487c1e516c 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 80b837a1aab..4fc2b871c7e 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 ac3f556a492..86455df2e98 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/57] 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 2f0c3249e34..c9aac594619 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/57] 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 0aa3c3ec354..53c75fe6ff5 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 aecac369c9b..426f6518358 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 67e8013471e..1502f11f101 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 34d6fea070c..d93dc0cac15 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 1eb68e4c121..79288afb144 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 b00b503e18d..e11f1114776 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 16142f28ea2..fba8d759863 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 506e49c30a2..e6a4296de07 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 669ecdcf6fe..31c18c34e29 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 936f458510e..d7a6b222e24 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 6b4e447919c..f33ff4dc4df 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 e4d04e92f5a..f23b378d7e8 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 a1146d581db..d9281301aaf 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 91997ccd5a9..02c434d073c 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 88e057ea6b5..5210ae83077 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 8848ff0d577..833e5f2df2c 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 e55deb7375f..878fdaed7bf 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 411b7018b43..9da7fd19a82 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 5c7f36c1a40..09169eae1fd 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 87054b17fa2..4770be57177 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 c81ddf93d96..7e531c5c7a9 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 d326fd53665..1edae70b079 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 00000000000..d859caff929 --- /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 cdf2db5d571..43945348d7d 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 157c985e658..d80da10164a 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 1b13671bce7..cf66b8fffca 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 5bf60d2087d..b3e7fa399c9 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 5487c1e516c..0621d596464 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 8ddd86a1176..855938f17de 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 0ac6a6e4db5..b69d6a0e5ee 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 7698de36ad3..6b1051d5c64 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 e97299f3db4..56375260466 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 4550ada6fc3..b1a6fa92635 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 a78fc1f5f50..75bdfa29e96 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 b274e733768..7b596432c74 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 4d278499df5..b88552afcdc 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 7888dfc6dc9..5ef1e2b7f04 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 8ba4e98896f..a3b5b3883bd 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 4fc2b871c7e..4ce5d578220 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 d637df6c392..272b5aca5ec 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 d4376eaeea0..9d9ef931d9f 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 1975e715cb1..67c172d08e1 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 062d7f8f924..00372a131e4 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 86455df2e98..0a5bcdb11fa 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 13cc452477d..46202e0c940 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 a56414eb6bc..977e9029468 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/57] 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 79288afb144..3596968f7b6 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 fba8d759863..24eb7466ec7 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 03651eaab9c..89e391cd9ec 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 1edae70b079..7d1252e8c1c 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 d859caff929..e0247677aa4 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 0621d596464..976439015ed 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 855938f17de..53f371f36fa 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 b69d6a0e5ee..96e4745a59c 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 b1a6fa92635..ecb68749731 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 75bdfa29e96..9e76b91e2b5 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 7b596432c74..be85de420f7 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 1f583a57854..578c8a72d80 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 4ce5d578220..dd90944a98a 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 272b5aca5ec..2f918baa2b7 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 9d9ef931d9f..01b9cc377ea 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 67c172d08e1..8cabe339605 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 56236fea500..b923439708f 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/57] 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 4eddf66cb74..79d1cad276b 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 fbbdede5ade..316e9b7a320 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/57] 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 983224bee91..3b3253885a3 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 89e391cd9ec..4c2a6490eb7 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 e0247677aa4..44de29c1fb6 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 828de805670..191825b18bb 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 578c8a72d80..8566ea04323 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 9cf66c7ff4b..e9285cd6273 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 b923439708f..6d7e8cbed6b 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 37bb8ca15ea..75119bfea28 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/57] 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 79d1cad276b..ebd619db1bd 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 44de29c1fb6..5ac003fcd90 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 316e9b7a320..2b470e044f8 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/57] 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 3596968f7b6..67714651cfb 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 191825b18bb..7657087732b 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/57] 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 3b3253885a3..178cdb821b6 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/57] 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 41d8c5551f0..b995fff888f 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 7db49c50490..4a1662ddf69 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 3973c61a0ee..2b4ac162300 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 ebbd50e0e7f..2939619e54f 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/57] 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 999192f20f3..8a9eb0a5a9f 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 b995fff888f..b9e32cc47a7 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 4a1662ddf69..0600293f331 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 fc42cd99f08..b8f75553eb0 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 00000000000..2d4ef63b382 --- /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 b493c3db2db..ee57d0f507b 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 d4b61e52af8..0a29bd92872 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 2b4ac162300..932fe15b5f8 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 00000000000..cb5fa84719a --- /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/57] 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 b9e32cc47a7..be2ec1e0129 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 0600293f331..eef4e592098 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 b8f75553eb0..a4609369e80 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 b43e4c8b427..f14121cec01 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 932fe15b5f8..7481b7374cd 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 9879b109412..8dd6bedcf18 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 cb5fa84719a..299ad9acb06 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/57] 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 b8f75553eb0..74603b822a5 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 2d4ef63b382..268a444d39c 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 cb5fa84719a..8ebc63e0821 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 00000000000..061f146f47b --- /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/57] 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 4c2a6490eb7..7041442e60e 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 5ac003fcd90..51b99f231cf 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 43945348d7d..031cd92ebf9 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 9e76b91e2b5..77e5ce4d0c4 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 7657087732b..a6cf7d63582 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 8566ea04323..c2af76c5c4d 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 75119bfea28..b51bc75c3fd 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 8fb20c7d758..7ef8cb7d50a 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/57] 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 dd90944a98a..2bab9a6f9df 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 88602f9b8d9..9dafc352f37 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/57] 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 756a7e12b52..1d1116ab267 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 00000000000..72b66087587 --- /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 00000000000..26d3e5a61b9 --- /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 00000000000..75f67b1e2f8 --- /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 00000000000..8c2fe40a76d --- /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 00000000000..5f57c7f9777 --- /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 00000000000..8b8da352a4a --- /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 00000000000..e194c5c519b --- /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 00000000000..d58bcae9b76 --- /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 00000000000..0920a735b54 --- /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 00000000000..47935684871 --- /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 d448c70c5ba..a204b39c64d 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 fd2236b77d6..7eeb3ace0b8 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/57] 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 1575e7cafc9..04733bba5c1 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 1d1116ab267..f4d8c9cc92c 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 72b66087587..718c5748ebf 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 00000000000..b256290fa58 --- /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 d447351bcc7..ee98b04a36b 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 7a5a816f70c..d2280a6f018 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 00000000000..33f59356bbd --- /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 00000000000..69843f23068 --- /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 00000000000..5b151533ee4 --- /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 6b474048163..e707c8bf66d 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 00000000000..9bc800e98ad --- /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 e69de29bb2d..00000000000 diff --git a/settings.gradle b/settings.gradle index 7ef8cb7d50a..9bcde28d03d 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 ca313baaa50..409a4f4e9e0 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/57] 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 71c2406fd93..59e6f02e66a 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 00000000000..8a7b6dc376d --- /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 00000000000..98ac0118824 --- /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/57] 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 af74eacec4b..ce8528831f7 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 04733bba5c1..d305e5c49e9 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 4ab12cc349c..6c401584abc 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 26d3e5a61b9..94443bd329d 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 00000000000..4d6f1764de5 --- /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 75f67b1e2f8..2fbebdba289 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 e7970939a98..15dfd3b165f 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 ee98b04a36b..d67b4e0bc79 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 00000000000..23227a593d5 --- /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 8a7b6dc376d..c3ba137b55c 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 69843f23068..73ba922d3e7 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 98ac0118824..4558952018c 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 00000000000..ffa16bae174 --- /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 5b151533ee4..89d267f2d97 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 00000000000..9fafd88c6cc --- /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 00000000000..113cdc148c7 --- /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 00000000000..4f000d97a14 --- /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 00000000000..a49900fbf3b --- /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 00000000000..2a57ab84dcb --- /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 9bc800e98ad..f8f873b922e 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 ff816873383..c7465209163 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 00000000000..2990549609a --- /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 c9975278838..461f16f9a76 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 620f98ae532..caa22df84fa 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 9bcde28d03d..e6273981a6f 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/57] 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 c32f33ec138..f1fcf04b296 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 00000000000..d314254b198 --- /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 00000000000..9e7d924a9ea --- /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 cb7b7ebe4cb..50aa7b38ba4 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 ecf53b02e46..9616fd55371 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 f7c10b3a566..2654f2113e6 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 00000000000..fc04294c6c3 --- /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 e6860cf2ca4..4416030fb7a 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 d683c9669f5..a78d0195bef 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 c3ba137b55c..62bc7090107 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 73ba922d3e7..99d35f6e8b1 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 4558952018c..bffffc59c53 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 ffa16bae174..7a872902905 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 00000000000..0872c8bb82e --- /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 00000000000..9f8a1a69a20 --- /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 00000000000..74ced4750d1 --- /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 00000000000..624bd1342fb --- /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 54dae5e62d9..a12293756e8 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 00000000000..5c377a7e1ac --- /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 00000000000..a07e1a2200e --- /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 2a57ab84dcb..d38e657a112 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 f6722d2ab68..59110db2479 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 c7a0ca09d2a..92076c712d9 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 832ac9be0fd..2b2bcc3ccc8 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 fbe0af4c847..3e7bba1ce39 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 f14121cec01..c4e6be98a55 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 0ad67c7fbcf..f1d40fec747 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/57] 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 f1fcf04b296..01e2ea196f7 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 00000000000..3a6d6a6a0da --- /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 d314254b198..e509ec623a8 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 9e7d924a9ea..d5da300c7b6 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 b2ec32d22ff..e8774960b46 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 b23671cfbc2..875b95e0997 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 6bd721bfb41..2cd2e69a6d2 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 00000000000..a3bc50a8f77 --- /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 718c5748ebf..94bc3fead2c 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 b256290fa58..77318ec9a4d 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 00000000000..b083ec1beb6 --- /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 94443bd329d..af6548bac13 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 4d6f1764de5..583b06cc4ef 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 2fbebdba289..00000000000 --- 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 95013512972..044a7225555 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 662c95add34..a11c60cc7d9 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 62bc7090107..16b2ed45230 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 99d35f6e8b1..8ad8dd866ff 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 bffffc59c53..6620dafc6f6 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 7a872902905..de0834fe89c 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 89d267f2d97..00000000000 --- 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 0872c8bb82e..ea6fef77273 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 624bd1342fb..a40c075219e 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 00000000000..59b430f31f4 --- /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 00000000000..ab2b8e3e139 --- /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 00000000000..d644580935f --- /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 00000000000..84b7863b7d7 --- /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 00000000000..e0e6a5e4c47 --- /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 00000000000..ea4bf7266a8 --- /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 00000000000..16f6647a611 --- /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 00000000000..598f53973ab --- /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 9f8a1a69a20..62cf7391b5e 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 74ced4750d1..8c67441b664 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 00000000000..a37a00eb451 --- /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 00000000000..1e7855d5c80 --- /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 00000000000..736491efdcd --- /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 e194c5c519b..cd376acef34 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 d58bcae9b76..365b08216e2 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 0920a735b54..685845d2b2c 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 00000000000..5a19fc77b26 --- /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 d38e657a112..81a5b8b7d33 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 00000000000..66b8cb3c9de --- /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 5e6b6793b35..813fd852cde 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 93d5a096d5e..3a580bb0069 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 00000000000..1f3855ed26b --- /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 00000000000..39448a6d543 --- /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 00000000000..fb990b1c191 --- /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 00000000000..e9e13467436 --- /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 00000000000..d1af8b4bfb2 --- /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 00000000000..5409b4efd26 --- /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 752e0bee92e..a4da2c75de0 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 00000000000..e290fed45e2 --- /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 1cfc92610c9..5ab44a57657 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 f1d40fec747..f0ec151570c 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 00000000000..a023c6dd0a4 --- /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 9b39a5ba729..e47637e2bc1 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/57] 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 2654f2113e6..89390c02554 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 a78d0195bef..6fb8d261c01 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 a12293756e8..af9641caa5c 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 4f40c6e4708..9abe90c3d77 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 92076c712d9..10c37bc1a60 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 9f16b6f6dff..64b4905a424 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/57] 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 ab2b8e3e139..36e567b4061 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 d644580935f..11c3388c366 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 00000000000..404f1ffaae8 --- /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 84b7863b7d7..94ab9647765 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 16f6647a611..ffea8ebd225 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 736491efdcd..79ecaa76350 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/57] 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 3a6d6a6a0da..cad75a1e84d 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 00000000000..6a128061bb1 --- /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 6fb8d261c01..6611bae64cc 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 00000000000..b3523c9cd22 --- /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 23227a593d5..de19fcac4fa 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 16b2ed45230..0fc74abd516 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 8ad8dd866ff..5160bcb4cf6 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 6620dafc6f6..552a72f1a61 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 de0834fe89c..fec3490312e 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 ea6fef77273..973495964ab 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 00000000000..69c1ac816d2 --- /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 00000000000..0b69c1fe81e --- /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 59b430f31f4..6eb262f640a 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 00000000000..985e4faf7ab --- /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 36e567b4061..093ba08583b 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 00000000000..101bf87d31c --- /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 11c3388c366..1e10b743e4b 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 94ab9647765..78a3def6570 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 e0e6a5e4c47..c67027611c0 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 00000000000..8bb94bf8ec3 --- /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 00000000000..b37979635d7 --- /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 ffea8ebd225..10ed5f84f70 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 598f53973ab..b4f22c751e0 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 00000000000..086566710a6 --- /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 a37a00eb451..d7d426c8bde 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 00000000000..04083fa0115 --- /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 00000000000..da9c4264bbf --- /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 8c67441b664..12196f009fe 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 1e7855d5c80..00000000000 --- 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 79ecaa76350..00000000000 --- 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 00000000000..a6a09de9b74 --- /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 00000000000..22eb2a4ec71 --- /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 00000000000..5057f4841db --- /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 af9641caa5c..bd3f0cb08be 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 00000000000..8d045c00951 --- /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 53465688768..6e3cbf96aca 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 6569eb2ca5d..0beeab7666c 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 ae9d65fc267..78387e8362a 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 a1f13cf757e..cc9525b0afe 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 f2d28ac8f06..194371d1735 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 00000000000..a4e4c088177 --- /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 f8f873b922e..f65f1651126 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 3a580bb0069..fa776a45038 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 1d470c935cd..ec74a7b4f1d 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 7eeb3ace0b8..8993764f975 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 2990549609a..ced07861c26 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 ff5c7ffad98..f24b8b56f0d 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 2db4e122018..0985cb6dca0 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 36060059490..8509e4c7861 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 7757f21723d..3857d13b765 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 e807bd8ef56..0c9283802ef 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 39448a6d543..fbae684cbb1 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 00000000000..971bc50d020 --- /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 d1af8b4bfb2..3aeee93c5de 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 00000000000..568db378b32 --- /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 f0ec151570c..869060a1775 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/57] 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 8cb7111ee6c..b9d29cdeea5 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 00000000000..0bcb680ca9a --- /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 00000000000..686d19fbabb --- /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 00000000000..ebcb0af8301 --- /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 00000000000..41459974fe3 --- /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 69c1ac816d2..283828139cf 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 6eb262f640a..6c0f7dd7cc3 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 d7d426c8bde..39243287c75 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 da9c4264bbf..0ffd861872a 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 a6a09de9b74..806e82e1db8 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, +) From 5d7a73333c142f407c2ffeb564bc3ee788a7e370 Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Sat, 11 Jul 2026 14:53:13 +0200 Subject: [PATCH 45/57] fix: adapt branch code to current main after merge - revert PropertyModification to non-generic (main's PropertyModifications map is built around it; generic form crashed kapt) - keep instance-keyed ModifiedEntitiesType; adapt LanguageStatsListener and QaActivityListener to entity-instance keys - move user-notification cleanup into ProjectHardDeletingService - align permission service/dto signatures with main (suggestLanguageIds, non-null base permission handling, wrapper-returning repository) - rename branch NotificationsTestData to UserNotificationsTestData (main introduced its own NotificationsTestData) - triage new ActivityTypes into the notification listener ignore list - ktlint format --- .../controllers/ProjectActivityController.kt | 1 + .../hateoas/activity/ActivityGroupModel.kt | 3 +- .../kotlin/io/tolgee/hateoas/key/KeyModel.kt | 1 + .../tolgee/hateoas/language/LanguageModel.kt | 3 +- .../notifications/UserNotificationModel.kt | 5 +- .../userAccount/SimpleUserAccountModel.kt | 2 +- .../SimpleUserAccountModelAssembler.kt | 17 ++++- .../activity/ActivityGroupModelEnhancer.kt | 27 +++---- .../activity/ModificationsSchemaGenerator.kt | 31 +++++--- .../activity/ProjectActivityModelEnhancer.kt | 39 ++++++----- .../configuration/openApi/activity/tools.kt | 3 +- .../activity/RootActivityProviderTest.kt | 13 ++-- .../groups/ActivityGroupsCreationTest.kt | 53 ++++++++------ .../groups/ProjectCreationGroupViewTest.kt | 3 +- .../KeyControllerCreationTest.kt | 1 - .../RemappedNotificationsTest.kt | 38 ++++------ .../UserNotificationDebounceTest.kt | 6 +- .../UserNotificationDispatchTest.kt | 24 ++++--- .../UserNotificationTranslationTest.kt | 18 +++-- .../KeyBaseTranslationDescriber.kt | 46 ++++++------ .../activity/data/PropertyModification.kt | 6 +- .../activity/groups/ActivityGroupType.kt | 3 +- .../tolgee/activity/groups/ActivityGrouper.kt | 47 +++++++------ .../activity/groups/ActivityGroupsProvider.kt | 70 +++++++++++-------- .../groups/data/DescribingEntityView.kt | 1 + .../groups/data/ModifiedEntityView.kt | 9 +-- .../groups/dataProviders/CountsProvider.kt | 28 ++++---- .../DescribingEntitiesProvider.kt | 6 +- .../groups/dataProviders/GroupDataProvider.kt | 22 +++--- .../RelevantModifiedEntitiesProvider.kt | 20 +++--- .../groups/matchers/EqualsValueMatcher.kt | 4 +- .../SetTranslationMatchingStringProvider.kt | 5 +- .../modifiedEntity/TranslationMatcher.kt | 4 +- .../createKey/CreateKeyGroupModelProvider.kt | 9 +-- .../CreateProjectGroupModelProvider.kt | 53 +++++++------- .../SetTranslationsGroupItemModel.kt | 2 +- .../SetTranslationsGroupModelProvider.kt | 3 +- .../rootActivity/ActivityItemsParser.kt | 13 ++-- .../rootActivity/ChildItemsProvider.kt | 10 +-- .../rootActivity/RootItemsProvider.kt | 3 +- .../views/ModifiedEntitiesViewProvider.kt | 12 ++-- .../processors/WebhookProcessor.kt | 3 +- .../eventListeners/LanguageStatsListener.kt | 12 +++- .../data/UserNotificationsTestData.kt | 18 ++--- .../io/tolgee/dtos/ComputedPermissionDto.kt | 2 +- .../kotlin/io/tolgee/model/UserAccount.kt | 2 +- .../activity/ActivityDescribingEntity.kt | 3 +- .../model/activity/ActivityModifiedEntity.kt | 3 +- ...missionsNotificationPreferencesDataView.kt | 4 +- .../model/views/UserProjectMetadataView.kt | 36 +++++----- .../NotificationPreferencesService.kt | 3 +- .../UserNotificationDebouncer.kt | 16 +++-- .../dispatchers/UserNotificationDispatch.kt | 3 +- .../listeners/ActivityEventListener.kt | 57 +++++++++++++++ .../listeners/BatchJobListener.kt | 3 +- .../tolgee/service/CachedPermissionService.kt | 3 +- .../project/ProjectHardDeletingService.kt | 4 +- .../service/security/PermissionService.kt | 14 ++-- .../src/main/kotlin/io/tolgee/util/dateExt.kt | 6 -- .../ee/component/qa/QaActivityListener.kt | 2 +- 60 files changed, 511 insertions(+), 347 deletions(-) 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 a409aa3b2ee..644a7a2bfd4 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 @@ -33,6 +33,7 @@ import io.tolgee.service.project.ProjectFeatureGuard import org.springdoc.core.annotations.ParameterObject import org.springframework.data.domain.Pageable import org.springframework.data.web.PagedResourcesAssembler +import org.springframework.hateoas.MediaTypes import org.springframework.hateoas.PagedModel import org.springframework.web.bind.annotation.CrossOrigin import org.springframework.web.bind.annotation.GetMapping 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 e509ec623a8..ea1ceaaea6c 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 @@ -15,4 +15,5 @@ class ActivityGroupModel( val author: SimpleUserAccountModel?, val data: Any?, var mentionedLanguageIds: List, -) : RepresentationModel(), Serializable +) : RepresentationModel(), + Serializable 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 963cdeb542b..848fb721530 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,5 +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 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 50aa7b38ba4..ea2be036fb5 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 @@ -19,4 +19,5 @@ open class LanguageModel( override var flagEmoji: String?, @Schema(example = "false", description = "Whether is base language of project") var base: Boolean, -) : RepresentationModel(), ILanguageModel +) : RepresentationModel(), + ILanguageModel 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 index 141050165e9..57d3595fe85 100644 --- a/backend/api/src/main/kotlin/io/tolgee/hateoas/notifications/UserNotificationModel.kt +++ b/backend/api/src/main/kotlin/io/tolgee/hateoas/notifications/UserNotificationModel.kt @@ -22,7 +22,7 @@ import io.tolgee.model.views.activity.SimpleModifiedEntityView import io.tolgee.notifications.NotificationType import org.springframework.hateoas.RepresentationModel import java.io.Serializable -import java.util.* +import java.util.Date @Suppress("unused") class UserNotificationModel( @@ -34,4 +34,5 @@ class UserNotificationModel( val unread: Boolean, val markedDoneAt: Date?, val lastUpdated: Date, -) : RepresentationModel(), Serializable +) : RepresentationModel(), + Serializable 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 de36bebef28..5e0cb6f8180 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 @@ -8,7 +8,7 @@ import org.springframework.hateoas.server.core.Relation 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 89390c02554..b3dfe736780 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,6 +3,7 @@ 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 @@ -10,11 +11,23 @@ import org.springframework.stereotype.Component @Component class SimpleUserAccountModelAssembler( private val avatarService: AvatarService, -) : RepresentationModelAssemblerSupport( +) : RepresentationModelAssemblerSupport( V2UserController::class.java, SimpleUserAccountModel::class.java, ) { - override fun toModel(entity: SimpleUserAccount): SimpleUserAccountModel { + override fun toModel(entity: UserAccount): SimpleUserAccountModel { + val avatar = avatarService.getAvatarLinks(entity.avatarHash) + + return SimpleUserAccountModel( + id = entity.id, + username = entity.username, + name = entity.name, + avatar = avatar, + deleted = entity.deletedAt != null, + ) + } + + fun toModel(entity: SimpleUserAccount): SimpleUserAccountModel { val avatar = avatarService.getAvatarLinks(entity.avatarHash) return SimpleUserAccountModel( 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 index a3bc50a8f77..76e4bdd669c 100644 --- 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 @@ -27,17 +27,19 @@ class ActivityGroupModelEnhancer( } private fun generateSchemas(): MutableList> { - return ActivityGroupType.entries.map { - val schemaName = it.getSchemaName() - Schema().apply { - name = schemaName - properties = getPropertiesForActivitySchema(it) - type = baseType - required = newRequired + 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 }) } - }.toMutableList().also { schemas -> - openApi.components.schemas.putAll(schemas.associateBy { it.name }) - } } private fun getPropertiesForActivitySchema(type: ActivityGroupType): MutableMap> { @@ -100,8 +102,9 @@ class ActivityGroupModelEnhancer( activityType: ActivityGroupType, ): Schema<*> { val oldTypeProperty = properties["type"] ?: throw IllegalStateException("Type property not found") - val newType = oldTypeProperty.clone() - @Suppress("TYPE_MISMATCH_WARNING") + + @Suppress("UNCHECKED_CAST") + val newType = oldTypeProperty.clone() as Schema newType.enum = newType.enum.filter { it == activityType.name } return newType } 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 94bc3fead2c..d623368e0e0 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 @@ -54,15 +54,17 @@ class ModificationsSchemaGenerator( val schemaSimpleProps = schema.properties?.filterKeys { it in simplePropNames } ?: emptyMap() val singlePropChangeMap = - schemaSimpleProps.map { (name, prop) -> - name to prop.toChangeSchema() - }.toMap() + 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() + complexProps + .map { + it.name to getModificationSchemaForComplexProp(it.returnType.classifier as KClass<*>) + }.toMap() return singlePropChangeMap + complexPropChangeMap } @@ -96,7 +98,8 @@ class ModificationsSchemaGenerator( private fun KClass<*>.getDescriptionProps(): List> { return memberProperties .filter { it.findAnnotation() != null } - .map { it }.filter { it.returnType.classifier.isSimpleType() } + .map { it } + .filter { it.returnType.classifier.isSimpleType() } } private fun List>.getSimpleProps(): List> { @@ -124,9 +127,17 @@ class ModificationsSchemaGenerator( 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, Map::class, + Int::class, + Long::class, + Double::class, + Float::class, + Boolean::class, + Char::class, + Byte::class, + Short::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 index 77318ec9a4d..db530047c85 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 @@ -32,17 +32,19 @@ class ProjectActivityModelEnhancer( } private fun generateSchemas(): MutableList> { - return ActivityType.entries.map { - val schemaName = it.getSchemaName() - Schema().apply { - name = schemaName - properties = getPropertiesForActivitySchema(it) - type = baseType - required = baseRequired + 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 }) } - }.toMutableList().also { schemas -> - openApi.components.schemas.putAll(schemas.associateBy { it.name }) - } } private fun getPropertiesForActivitySchema(activityType: ActivityType): MutableMap> { @@ -54,11 +56,13 @@ class ProjectActivityModelEnhancer( private fun getNewModifiedEntitiesProperty(activityType: ActivityType): Schema { val properties = - activityType.typeDefinitions?.map { (entityClass, definition) -> - val schema = activityType.createModifiedEntityModel(entityClass) - schema.properties["modifications"] = ModificationsSchemaGenerator(openApi).getModificationSchema(entityClass, definition) - entityClass.simpleName to schema - }?.toMap() + activityType.typeDefinitions + ?.map { (entityClass, definition) -> + val schema = activityType.createModifiedEntityModel(entityClass) + schema.properties["modifications"] = + ModificationsSchemaGenerator(openApi).getModificationSchema(entityClass, definition) + entityClass.simpleName to schema + }?.toMap() return Schema().apply { name = activityType.getModifiedEntitiesSchemaName() @@ -71,8 +75,9 @@ class ProjectActivityModelEnhancer( activityType: ActivityType, ): Schema<*> { val oldTypeProperty = properties["type"] ?: throw IllegalStateException("Type property not found") - val newType = oldTypeProperty.clone() - @Suppress("TYPE_MISMATCH_WARNING") + + @Suppress("UNCHECKED_CAST") + val newType = oldTypeProperty.clone() as Schema newType.enum = newType.enum.filter { it == activityType.name } return newType } 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 index b083ec1beb6..4e4113255ac 100644 --- 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 @@ -11,7 +11,8 @@ fun getEntitySchema( entityClass: KClass<*>, ): Schema<*> { val resolved = - ModelConverters.getInstance() + ModelConverters + .getInstance() .readAllAsResolvedSchema(AnnotatedType(entityClass.java)) resolved.referencedSchemas.forEach(openApi.components.schemas::putIfAbsent) 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 af6548bac13..c67d8994ee7 100644 --- a/backend/app/src/test/kotlin/io/tolgee/activity/RootActivityProviderTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/activity/RootActivityProviderTest.kt @@ -24,10 +24,11 @@ class RootActivityProviderTest : ProjectAuthControllerTest("/v2/projects/") { } private fun getLatestRevisionId(): Long? { - return entityManager.createQuery( - "select max(r.id) from ActivityRevision r", - Long::class.java, - ).singleResult + return entityManager + .createQuery( + "select max(r.id) from ActivityRevision r", + Long::class.java, + ).singleResult } private fun importData() { @@ -37,7 +38,9 @@ class RootActivityProviderTest : ProjectAuthControllerTest("/v2/projects/") { testData.setAllResolved() testData.setAllOverride() testDataService.saveTestData(testData.root) - val user = testData.root.data.userAccounts[0].self + val user = + testData.root.data.userAccounts[0] + .self val projectId = testData.project.id loginAsUser(user.username) val path = "/v2/projects/$projectId/import/apply" 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 583b06cc4ef..09d1a7beeb5 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 @@ -1,6 +1,6 @@ package io.tolgee.activity.groups -import com.posthog.java.PostHog +import com.posthog.server.PostHog import io.tolgee.ProjectAuthControllerTest import io.tolgee.batch.BatchJobService import io.tolgee.development.testDataBuilder.data.BaseTestData @@ -18,13 +18,11 @@ 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 java.time.Duration class ActivityGroupsCreationTest : ProjectAuthControllerTest("/v2/projects/") { private lateinit var testData: BaseTestData - @MockBean @Autowired lateinit var postHog: PostHog @@ -137,16 +135,17 @@ class ActivityGroupsCreationTest : ProjectAuthControllerTest("/v2/projects/") { val activityRevision = findLastActivityRevision() val groups = getActivityGroupsForRevision(activityRevision) val group = groups.single() - entityManager.createQuery( - """ + entityManager + .createQuery( + """ select count(ar) from ActivityRevision ar join ar.activityGroups ag where ag.id = :groupId """, - ) - .setParameter("groupId", group.id) + ).setParameter("groupId", group.id) .singleResult - .assert.isEqualTo(count.toLong()) + .assert + .isEqualTo(count.toLong()) } } @@ -162,7 +161,10 @@ class ActivityGroupsCreationTest : ProjectAuthControllerTest("/v2/projects/") { executeInNewTransaction { val activityRevision = findLastActivityRevision() val groups = getActivityGroupsForRevision(activityRevision) - groups.single().type.assert.isEqualTo(activityGroupType) + groups + .single() + .type.assert + .isEqualTo(activityGroupType) } } @@ -172,10 +174,12 @@ class ActivityGroupsCreationTest : ProjectAuthControllerTest("/v2/projects/") { val groups = getActivityGroupsForRevision(activityRevision) val group = groups.single() val modifiedEntities = getModifiedEntitiesForGroup(group) - modifiedEntities.filter { it.entityClass == Translation::class.simpleName } + modifiedEntities + .filter { it.entityClass == Translation::class.simpleName } .last() .modifications["text"]!! - .new.assert.isEqualTo(value) + .new.assert + .isEqualTo(value) } } @@ -187,39 +191,42 @@ class ActivityGroupsCreationTest : ProjectAuthControllerTest("/v2/projects/") { } private fun findLastActivityRevision(): ActivityRevision { - return entityManager.createQuery( - """ + return entityManager + .createQuery( + """ select ar from ActivityRevision ar order by ar.timestamp desc limit 1 """, - ActivityRevision::class.java, - ).singleResult + ActivityRevision::class.java, + ).singleResult } private fun getActivityGroupsForRevision(activityRevision: ActivityRevision): MutableList { - return entityManager.createQuery( - """ + return entityManager + .createQuery( + """ select ag from ActivityGroup ag join fetch ag.activityRevisions ar where ar.id = :activityRevisionId """, - ActivityGroup::class.java, - ).setParameter("activityRevisionId", activityRevision.id) + ActivityGroup::class.java, + ).setParameter("activityRevisionId", activityRevision.id) .resultList } private fun getModifiedEntitiesForGroup(group: ActivityGroup): MutableList { - return entityManager.createQuery( - """ + 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) + ActivityModifiedEntity::class.java, + ).setParameter("groupId", group.id) .resultList } } 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 index fc04294c6c3..a3c885d10c0 100644 --- a/backend/app/src/test/kotlin/io/tolgee/activity/groups/ProjectCreationGroupViewTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/activity/groups/ProjectCreationGroupViewTest.kt @@ -34,7 +34,8 @@ class ProjectCreationGroupViewTest : AuthorizedControllerTest() { userAccount = testData.user val projectId = performProjectCreation() performAuthGet("/v2/projects/$projectId/activity/groups") - .andIsOk.andAssertThatJson { + .andIsOk + .andAssertThatJson { node("_embedded.groups") { isArray.hasSizeGreaterThan(0) node("[0]") { 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 41d6f7763c9..c959f7edac1 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 @@ -27,7 +27,6 @@ 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 import org.junit.jupiter.api.assertThrows 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 e11f1114776..963d7c3da3c 100644 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/RemappedNotificationsTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/RemappedNotificationsTest.kt @@ -16,24 +16,24 @@ package io.tolgee.notifications -import io.tolgee.development.testDataBuilder.data.NotificationsTestData +import io.tolgee.development.testDataBuilder.data.UserNotificationsTestData 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.fixtures.generateImage 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 + lateinit var testData: UserNotificationsTestData @BeforeEach override fun setupTests() { - testData = NotificationsTestData() + testData = UserNotificationsTestData() testDataService.saveTestData(testData.root) super.setupTests() @@ -91,8 +91,7 @@ class RemappedNotificationsTest : AbstractNotificationTest() { .satisfiesOnlyOnce { it.type.assert.isEqualTo(NotificationType.ACTIVITY_TRANSLATIONS_UPDATED) it.modifiedEntities.assert.hasSize(1) - } - .satisfiesOnlyOnce { + }.satisfiesOnlyOnce { it.type.assert.isEqualTo(NotificationType.ACTIVITY_KEYS_CREATED) it.modifiedEntities.assert.hasSize(8) // 2 keys + 6 translations } @@ -102,8 +101,7 @@ class RemappedNotificationsTest : AbstractNotificationTest() { .satisfiesOnlyOnce { it.type.assert.isEqualTo(NotificationType.ACTIVITY_TRANSLATIONS_UPDATED) it.modifiedEntities.assert.hasSize(1) - } - .satisfiesOnlyOnce { + }.satisfiesOnlyOnce { it.type.assert.isEqualTo(NotificationType.ACTIVITY_KEYS_CREATED) it.modifiedEntities.assert.hasSize(8) // 2 keys + 6 translations } @@ -113,8 +111,7 @@ class RemappedNotificationsTest : AbstractNotificationTest() { .satisfiesOnlyOnce { it.type.assert.isEqualTo(NotificationType.ACTIVITY_TRANSLATIONS_UPDATED) it.modifiedEntities.assert.hasSize(1) - } - .satisfiesOnlyOnce { + }.satisfiesOnlyOnce { it.type.assert.isEqualTo(NotificationType.ACTIVITY_KEYS_CREATED) it.modifiedEntities.assert.hasSize(6) // 2 keys + 4 translations } @@ -140,8 +137,7 @@ class RemappedNotificationsTest : AbstractNotificationTest() { .satisfiesOnlyOnce { it.type.assert.isEqualTo(NotificationType.ACTIVITY_TRANSLATIONS_UPDATED) it.modifiedEntities.assert.hasSize(1) - } - .satisfiesOnlyOnce { + }.satisfiesOnlyOnce { it.type.assert.isEqualTo(NotificationType.ACTIVITY_KEYS_CREATED) it.modifiedEntities.assert.hasSize(8) // 2 keys + 6 translations } @@ -151,8 +147,7 @@ class RemappedNotificationsTest : AbstractNotificationTest() { .satisfiesOnlyOnce { it.type.assert.isEqualTo(NotificationType.ACTIVITY_TRANSLATIONS_UPDATED) it.modifiedEntities.assert.hasSize(1) - } - .satisfiesOnlyOnce { + }.satisfiesOnlyOnce { it.type.assert.isEqualTo(NotificationType.ACTIVITY_KEYS_CREATED) it.modifiedEntities.assert.hasSize(8) // 2 keys + 6 translations } @@ -204,15 +199,12 @@ class RemappedNotificationsTest : AbstractNotificationTest() { .hasSize(4) .satisfiesOnlyOnce { it.type.assert.isEqualTo(NotificationType.ACTIVITY_KEYS_UPDATED) - } - .satisfiesOnlyOnce { + }.satisfiesOnlyOnce { it.type.assert.isEqualTo(NotificationType.ACTIVITY_KEYS_SCREENSHOTS_UPLOADED) - } - .satisfiesOnlyOnce { + }.satisfiesOnlyOnce { it.type.assert.isEqualTo(NotificationType.ACTIVITY_SOURCE_STRINGS_UPDATED) it.modifiedEntities.assert.hasSize(1) - } - .satisfiesOnlyOnce { + }.satisfiesOnlyOnce { it.type.assert.isEqualTo(NotificationType.ACTIVITY_TRANSLATIONS_UPDATED) it.modifiedEntities.assert.hasSize(1) } @@ -221,11 +213,9 @@ class RemappedNotificationsTest : AbstractNotificationTest() { .hasSize(3) .satisfiesOnlyOnce { it.type.assert.isEqualTo(NotificationType.ACTIVITY_KEYS_UPDATED) - } - .satisfiesOnlyOnce { + }.satisfiesOnlyOnce { it.type.assert.isEqualTo(NotificationType.ACTIVITY_KEYS_SCREENSHOTS_UPLOADED) - } - .satisfiesOnlyOnce { + }.satisfiesOnlyOnce { it.type.assert.isEqualTo(NotificationType.ACTIVITY_SOURCE_STRINGS_UPDATED) it.modifiedEntities.assert.hasSize(1) } 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 24eb7466ec7..de4093696eb 100644 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt @@ -16,7 +16,7 @@ package io.tolgee.notifications -import io.tolgee.development.testDataBuilder.data.NotificationsTestData +import io.tolgee.development.testDataBuilder.data.UserNotificationsTestData import io.tolgee.dtos.request.LanguageRequest import io.tolgee.dtos.request.key.CreateKeyDto import io.tolgee.dtos.request.translation.comment.TranslationCommentWithLangKeyDto @@ -27,11 +27,11 @@ import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test class UserNotificationDebounceTest : AbstractNotificationTest() { - lateinit var testData: NotificationsTestData + lateinit var testData: UserNotificationsTestData @BeforeEach override fun setupTests() { - testData = NotificationsTestData() + testData = UserNotificationsTestData() testDataService.saveTestData(testData.root) super.setupTests() 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 e6a4296de07..5f2ee1fc24d 100644 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDispatchTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDispatchTest.kt @@ -16,23 +16,23 @@ package io.tolgee.notifications -import io.tolgee.development.testDataBuilder.data.NotificationsTestData +import io.tolgee.development.testDataBuilder.data.UserNotificationsTestData 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.fixtures.generateImage 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 + lateinit var testData: UserNotificationsTestData @BeforeEach override fun setupTests() { - testData = NotificationsTestData() + testData = UserNotificationsTestData() testDataService.saveTestData(testData.root) super.setupTests() @@ -174,11 +174,17 @@ class UserNotificationDispatchTest : AbstractNotificationTest() { 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) + frenchTranslatorNotifications[0] + .modifiedEntities + .first() + .entityId.assert + .isEqualTo(testData.key1FrTranslation.id) + + czechTranslatorNotifications[0] + .modifiedEntities + .first() + .entityId.assert + .isEqualTo(testData.key1CzTranslation.id) 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 d7a6b222e24..b062263b611 100644 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationTranslationTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationTranslationTest.kt @@ -16,7 +16,7 @@ package io.tolgee.notifications -import io.tolgee.development.testDataBuilder.data.NotificationsTestData +import io.tolgee.development.testDataBuilder.data.UserNotificationsTestData import io.tolgee.dtos.request.key.CreateKeyDto import io.tolgee.dtos.request.translation.SetTranslationsWithKeyDto import io.tolgee.fixtures.andIsCreated @@ -26,11 +26,11 @@ import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test class UserNotificationTranslationTest : AbstractNotificationTest() { - lateinit var testData: NotificationsTestData + lateinit var testData: UserNotificationsTestData @BeforeEach override fun setupTests() { - testData = NotificationsTestData() + testData = UserNotificationsTestData() testDataService.saveTestData(testData.root) super.setupTests() @@ -49,7 +49,9 @@ class UserNotificationTranslationTest : AbstractNotificationTest() { waitUntilUserNotificationDispatch() - userNotificationRepository.findAllByRecipient(testData.alice).assert + userNotificationRepository + .findAllByRecipient(testData.alice) + .assert .satisfiesOnlyOnce { it.type.assert.isEqualTo(NotificationType.ACTIVITY_SOURCE_STRINGS_UPDATED) } .noneSatisfy { it.type.assert.isEqualTo(NotificationType.ACTIVITY_TRANSLATIONS_UPDATED) } @@ -64,7 +66,9 @@ class UserNotificationTranslationTest : AbstractNotificationTest() { waitUntilUserNotificationDispatch() - userNotificationRepository.findAllByRecipient(testData.alice).assert + userNotificationRepository + .findAllByRecipient(testData.alice) + .assert .satisfiesOnlyOnce { it.type.assert.isEqualTo(NotificationType.ACTIVITY_SOURCE_STRINGS_UPDATED) } .satisfiesOnlyOnce { it.type.assert.isEqualTo(NotificationType.ACTIVITY_TRANSLATIONS_UPDATED) } } @@ -105,7 +109,9 @@ class UserNotificationTranslationTest : AbstractNotificationTest() { waitUntilUserNotificationDispatch() - userNotificationRepository.findAllByRecipient(testData.alice).assert + userNotificationRepository + .findAllByRecipient(testData.alice) + .assert .noneMatch { it.type == NotificationType.ACTIVITY_TRANSLATION_OUTDATED } .noneMatch { it.type == NotificationType.ACTIVITY_TRANSLATIONS_UPDATED } } 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 index b3523c9cd22..74c7818a19c 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/additionalDescribers/KeyBaseTranslationDescriber.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/additionalDescribers/KeyBaseTranslationDescriber.kt @@ -28,9 +28,10 @@ class KeyBaseTranslationDescriber( 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() + 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 @@ -88,11 +89,11 @@ class KeyBaseTranslationDescriber( 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()) + 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 @@ -122,24 +123,27 @@ class KeyBaseTranslationDescriber( ): 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() + 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() + 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? 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 b9d29cdeea5..8cb7111ee6c 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: T?, - val new: T?, +data class PropertyModification( + val old: Any?, + val new: Any?, ) 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 5160bcb4cf6..8e8f76d7b6b 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 @@ -461,7 +461,8 @@ enum class ActivityGroupType( ?.arguments ?: return null val groupType = - arguments.firstOrNull() + arguments + .firstOrNull() ?.type ?.classifier as? KClass<*> 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 552a72f1a61..9e514157ffc 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 @@ -22,13 +22,13 @@ class ActivityGrouper( } private fun addToGroup(groupId: Long) { - entityManager.createNativeQuery( - """ + entityManager + .createNativeQuery( + """ insert into activity_revision_activity_groups (activity_revisions_id, activity_groups_id) values (:activityRevisionId, :activityGroupId) """, - ) - .setParameter("activityRevisionId", activityRevision.id) + ).setParameter("activityRevisionId", activityRevision.id) .setParameter("activityGroupId", groupId) .executeUpdate() } @@ -37,27 +37,30 @@ class ActivityGrouper( type: ActivityGroupType, matchingStrings: Set, ): Map { - return activityGroupService.getOrCreateCurrentActivityGroupDto( - type, - matchingStrings, - activityRevision.projectId, - activityRevision.authorId, - ).mapValues { it.value.id } + return activityGroupService + .getOrCreateCurrentActivityGroupDto( + type, + matchingStrings, + activityRevision.projectId, + activityRevision.authorId, + ).mapValues { it.value.id } } 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() + 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.matchingEntities: List 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 fec3490312e..0c1b4540bc5 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 @@ -16,7 +16,7 @@ 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.* +import java.util.Date class ActivityGroupsProvider( val projectId: Long, @@ -54,41 +54,52 @@ class ActivityGroupsProvider( where = where.and(field("ag.author_id").`in`(filters.filterAuthorUserIdIn)) } - val count = jooqContext.selectCount().from(from).where(where).fetchOne(0, Long::class.java)!! + 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")), - field("ua.id"), - field("ua.username"), - field("ua.name"), - field("ua.avatar_hash"), - field("ua.deleted_at").isNotNull, - lmeJsonArrayAggField, - ldeJsonArrayAggField, - ) - .from(from) + jooqContext + .select( + field("ag.id"), + 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, + lmeJsonArrayAggField, + ldeJsonArrayAggField, + ).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"))) - .leftJoin(table("activity_modified_entity").`as`("lme")).on( - field("ar.id").eq(field("lme.activity_revision_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")) + ).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) + ).where(where) .groupBy(field("ag.id"), field("ua.id")) .having(having) .orderBy(max(field("ar.timestamp")).desc(), orderedTypesField?.desc()) .limit(pageable.pageSize) - .offset(pageable.offset).fetch().map { + .offset(pageable.offset) + .fetch() + .map { ActivityGroupView( it[0] as Long, ActivityGroupType.valueOf(it[1] as String), @@ -120,11 +131,12 @@ class ActivityGroupsProvider( } private val dataViews by lazy { - byType.flatMap { (type, items) -> - val provider = - type.modelProviderFactoryClass?.let { applicationContext.getBean(it.java) } - provider?.provideGroup(items.map { it.id })?.map { it.key to it.value } ?: emptyList() - }.toMap() + byType + .flatMap { (type, items) -> + val provider = + type.modelProviderFactoryClass?.let { applicationContext.getBean(it.java) } + provider?.provideGroup(items.map { it.id })?.map { it.key to it.value } ?: emptyList() + }.toMap() } private val byType by lazy { page.groupBy { it.type } } 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 283828139cf..8a168a5cd70 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 @@ -8,6 +8,7 @@ class DescribingEntityView( val data: Map, val describingRelations: Map, override val activityRevisionId: Long, + override val additionalDescription: Map? = null, ) : ActivityEntityView { inline fun getFieldFromViewNullable(name: String): T? { return this.data[name] as? T 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 6c0f7dd7cc3..42b44967e1b 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 @@ -4,10 +4,11 @@ import io.tolgee.activity.data.EntityDescriptionRef import io.tolgee.activity.data.PropertyModification class ModifiedEntityView( - val entityId: Long, - val entityClass: String, + override val entityId: Long, + override val entityClass: String, val describingData: Map, val describingRelations: Map, - val modifications: Map>, - val activityRevisionId: Long, + val modifications: Map, + override val activityRevisionId: Long, + override val additionalDescription: Map? = null, ) : ActivityEntityView 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 093ba08583b..70ee84f08f5 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 @@ -28,28 +28,27 @@ class CountsProvider( groupIdField, entityClassField, countField, - ) - .from(activityModifiedEntityTable) + ).from(activityModifiedEntityTable) .join(activityRevisionTable) .on( - DSL.field("ame.activity_revision_id", Long::class.java) + DSL + .field("ame.activity_revision_id", Long::class.java) .eq(DSL.field("ar.id", Long::class.java)), - ) - .join(activityRevisionActivityGroupsTable) + ).join(activityRevisionActivityGroupsTable) .on( - DSL.field("ar.id", Long::class.java) + DSL + .field("ar.id", Long::class.java) .eq(DSL.field("arag.activity_revisions_id", Long::class.java)), - ) - .join(activityGroupTable).on( + ).join(activityGroupTable) + .on( groupIdField.eq(DSL.field("ag.id", Long::class.java)), - ) - .where( - groupIdField.`in`(groupIds) + ).where( + groupIdField + .`in`(groupIds) .and(entityClassField.`in`(entityClasses)) .and(groupType.matcher?.match(sqlContext)) .and(getStringMatcherCondition()), - ) - .groupBy(entityClassField, groupIdField) + ).groupBy(entityClassField, groupIdField) .fetch() return queryResult.groupBy { groupIdField.get(it)!! }.mapValues { rows -> @@ -69,7 +68,8 @@ class CountsProvider( } private fun getStringMatcherCondition(): Condition { - return groupType.matchingStringProvider?.provide(sqlContext) + 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 index 101bf87d31c..142a9ae200d 100644 --- 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 @@ -24,7 +24,8 @@ class DescribingEntitiesProvider( fun provide(): Map> { val views = - query.fetch() + query + .fetch() .map { DescribingEntityView( entityId = it.get(entityIdField), @@ -58,7 +59,8 @@ class DescribingEntitiesProvider( val condition by lazy { DSL.or( refs.map { (entity, ref) -> - DSL.condition(entityClassField.eq(ref.entityClass)) + DSL + .condition(entityClassField.eq(ref.entityClass)) .and(entityIdField.eq(ref.entityId)) .and(activityRevisionIdField.eq(entity.activityRevisionId)) }, 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 1e10b743e4b..737baab16a0 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 @@ -34,9 +34,10 @@ class GroupDataProvider( jooqContext = jooqContext, ).provide() - return result.map { (groupId, counts) -> - groupId to (counts[simpleNameString] ?: 0) - }.toMap() + return result + .map { (groupId, counts) -> + groupId to (counts[simpleNameString] ?: 0) + }.toMap() } fun provideRelevantModifiedEntities( @@ -74,17 +75,16 @@ class GroupDataProvider( DSL .and( context.groupIdField.eq(groupId), - ) - .and( + ).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)) + DSL + .condition( + "(${context.describingRelationsField.name} -> ? -> 'entityId')::bigint = ?", + mapping.field, + it.entityId, + ).and(context.entityClassField.eq(mapping.entityClass.simpleName)) } }, ), 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 78a3def6570..ace23682570 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 @@ -46,18 +46,20 @@ class RelevantModifiedEntitiesProvider( .from(activityModifiedEntityTable) .join(activityRevisionTable) .on( - DSL.field("ame.activity_revision_id", Long::class.java) + DSL + .field("ame.activity_revision_id", Long::class.java) .eq(DSL.field("ar.id", Long::class.java)), - ) - .join(activityRevisionActivityGroupsTable) + ).join(activityRevisionActivityGroupsTable) .on( - DSL.field("ar.id", Long::class.java) + DSL + .field("ar.id", Long::class.java) .eq(DSL.field("arag.activity_revisions_id", Long::class.java)), - ) - .where( - DSL.and(entityClassField.`in`(entityClasses)).and( - groupType.matcher?.match(sqlContext), - ).and(additionalFilter?.let { it(sqlContext) } ?: DSL.noCondition()), + ).where( + DSL + .and(entityClassField.`in`(entityClasses)) + .and( + groupType.matcher?.match(sqlContext), + ).and(additionalFilter?.let { it(sqlContext) } ?: DSL.noCondition()), ) private fun getDataQuery() = 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 index 113cdc148c7..5ce8565d784 100644 --- 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 @@ -7,7 +7,9 @@ import org.jooq.Field import org.jooq.JSON import org.jooq.impl.DSL -class EqualsValueMatcher(val value: Any?) : ActivityGroupValueMatcher { +class EqualsValueMatcher( + val value: Any?, +) : ActivityGroupValueMatcher { override fun match(value: Any?): Boolean { if (value is PropertyModification) { return value.new == this.value 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 index b37979635d7..bbc5052e202 100644 --- 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 @@ -9,7 +9,10 @@ class SetTranslationMatchingStringProvider : MatchingStringProvider { if (context.modifiedEntity.entityClass != Translation::class.simpleName) { return null } - return context.modifiedEntity.describingRelations?.get("language")?.entityId?.toString() + return context.modifiedEntity.describingRelations + ?.get("language") + ?.entityId + ?.toString() ?: throw IllegalStateException("Language not found") } 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 index 086566710a6..ebe73496c30 100644 --- 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 @@ -26,7 +26,9 @@ class TranslationMatcher( } val entityId = - context.modifiedEntity.describingRelations?.get("language")?.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 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 0ffd861872a..dca76ec125e 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 @@ -18,8 +18,7 @@ import org.springframework.stereotype.Component @Component class CreateKeyGroupModelProvider( private val groupDataProvider: GroupDataProvider, -) : - GroupModelProvider { +) : GroupModelProvider { override fun provideGroup(groupIds: List): Map { val keyCounts = groupDataProvider.provideCounts(ActivityGroupType.CREATE_KEY, groupIds = groupIds, entityClass = Key::class) @@ -77,10 +76,12 @@ class CreateKeyGroupModelProvider( return entities.map { entity -> val baseTranslation = relatedEntities[entity] - ?.get(translationMapping)?.singleOrNull() + ?.get(translationMapping) + ?.singleOrNull() val baseTranslationText = - baseTranslation?.modifications + baseTranslation + ?.modifications ?.get("text") ?.new as? 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 12196f009fe..852a9038ad8 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 @@ -11,8 +11,7 @@ import org.springframework.stereotype.Component @Component class CreateProjectGroupModelProvider( private val jooqContext: DSLContext, -) : - GroupModelProvider { +) : GroupModelProvider { override fun provideGroup(groupIds: List): Map { val query = jooqContext @@ -26,41 +25,43 @@ class CreateProjectGroupModelProvider( 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")) + ).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")) + 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)) + ).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 { - ActivityGroupLanguageModel( - it["languageId"] as Long, - it["languageName"] as String, - it["languageOriginalName"] as String, - it["languageTag"] as String, - it["languageFlagEmoji"] as String, - ) - } + return query + .groupBy { it["groupId"] as Long } + .map { (id, rows) -> + 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, - ) - }.toMap() + id to + CreateProjectGroupModel( + id = id, + name = rows.first()["name"] as String, + description = rows.first()["description"] as String?, + languages = languages, + ) + }.toMap() } override fun provideItems( 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 806e82e1db8..6337f6cd39b 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 @@ -7,6 +7,6 @@ import org.springframework.hateoas.server.core.Relation @Relation(collectionRelation = "items", itemRelation = "item") class SetTranslationsGroupItemModel( val id: Long, - val text: PropertyModification, + val text: PropertyModification, val key: ActivityGroupKeyModel, ) 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 index 5057f4841db..8d0c72fb6c4 100644 --- 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 @@ -11,8 +11,7 @@ import org.springframework.stereotype.Component @Component class SetTranslationsGroupModelProvider( private val groupDataProvider: GroupDataProvider, -) : - GroupModelProvider { +) : GroupModelProvider { override fun provideGroup(groupIds: List): Map { val translationCounts = groupDataProvider.provideCounts( 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 index 8c2fe40a76d..c7dccb1ca7d 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/ActivityItemsParser.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/rootActivity/ActivityItemsParser.kt @@ -47,10 +47,11 @@ class ActivityItemsParser( } private fun getNewFromModifications(modifications: Map?): Map? { - return modifications?.map { - @Suppress("UNCHECKED_CAST") - it.key to ((it.value as? Map)?.get("new")) - }?.toMap() + return modifications + ?.map { + @Suppress("UNCHECKED_CAST") + it.key to ((it.value as? Map)?.get("new")) + }?.toMap() } private fun Any?.parseJsonOrNull(): Map? { @@ -64,7 +65,9 @@ class ActivityItemsParser( return null } - enum class Type(val value: String) { + enum class Type( + val value: String, + ) { MODIFIED_ENTITY("AME"), DESCRIBING_ENTITY("ADE"), ; 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 cd376acef34..51db2a4ffd1 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 @@ -15,8 +15,9 @@ class ChildItemsProvider( } private fun getItemsRaw(): List> { - return entityManager.createNativeQuery( - """ + 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 @@ -38,9 +39,8 @@ class ChildItemsProvider( ) order by id """, - Array::class.java, - ) - .setParameter("entityClass", treeItem.entityClass.simpleName) + Array::class.java, + ).setParameter("entityClass", treeItem.entityClass.simpleName) .setParameter("describingField", treeItem.describingField) .setParameter("revisionIds", activityRevisionId) .setParameter("ids", parentIds) 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 685845d2b2c..75519cb6749 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 @@ -71,7 +71,8 @@ class RootItemsProvider( .and(adeEntityId.notIn(adeSubQuery)) val unionQuery = - ameSelect.unionAll(adeSelect) + ameSelect + .unionAll(adeSelect) .orderBy(field("id")) .limit(limit) .offset(offset) 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 334e3c5f890..bf9c66ead74 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 @@ -94,14 +94,14 @@ class ModifiedEntitiesViewProvider( }, ), ) - } - ?.toMap() + }?.toMap() } private fun fetchAllowedRevisionRelations(): Map> { val revisionIds = modifiedEntities.map { it.activityRevision.id } val allowedTypes = ActivityType.entries.filter { !it.onlyCountsInList } - return activityRevisionRepository.getRelationsForRevisions(revisionIds, allowedTypes) + return activityRevisionRepository + .getRelationsForRevisions(revisionIds, allowedTypes) .groupBy { it.activityRevision.id } } @@ -126,8 +126,7 @@ class ModifiedEntitiesViewProvider( 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 } } + }.flatMap { (entityClassName, existingIds) -> existingIds.map { (entityClassName to it.first) to it.second } } .toMap() } @@ -138,7 +137,8 @@ class ModifiedEntitiesViewProvider( val entity = describingEntities.find { it.entityClass == value.entityClass && it.entityId == value.entityId } val relations = - entity?.describingRelations + entity + ?.describingRelations ?.map { it.key to extractCompressedRef(it.value, describingEntities) } ?.toMap() diff --git a/backend/data/src/main/kotlin/io/tolgee/component/automations/processors/WebhookProcessor.kt b/backend/data/src/main/kotlin/io/tolgee/component/automations/processors/WebhookProcessor.kt index 6b90c0eca4a..b75ed1cc572 100644 --- a/backend/data/src/main/kotlin/io/tolgee/component/automations/processors/WebhookProcessor.kt +++ b/backend/data/src/main/kotlin/io/tolgee/component/automations/processors/WebhookProcessor.kt @@ -27,8 +27,7 @@ class WebhookProcessor( activityRevisionId: Long?, ) { activityRevisionId ?: return - val projectId = action.automation.project.id - val view = activityService.getProjectActivity(projectId = projectId, revisionId = activityRevisionId) ?: return + val view = activityService.findProjectActivity(activityRevisionId) ?: return val activityModel = activityModelAssembler.toModel(view) val config = action.webhookConfig ?: return if (!config.enabled) return diff --git a/backend/data/src/main/kotlin/io/tolgee/component/eventListeners/LanguageStatsListener.kt b/backend/data/src/main/kotlin/io/tolgee/component/eventListeners/LanguageStatsListener.kt index 410c373d3ad..9692f3ed7f4 100644 --- a/backend/data/src/main/kotlin/io/tolgee/component/eventListeners/LanguageStatsListener.kt +++ b/backend/data/src/main/kotlin/io/tolgee/component/eventListeners/LanguageStatsListener.kt @@ -134,7 +134,11 @@ class LanguageStatsListener( event: OnProjectActivityEvent, branchIds: MutableSet, ) { - val keyIds = event.modifiedEntities[Key::class]?.keys.orEmpty() + val keyIds = + event.modifiedEntities[Key::class] + ?.keys + .orEmpty() + .map { it.id } if (keyIds.isEmpty()) return keyIds.chunked(IN_CLAUSE_BATCH_SIZE).forEach { chunk -> @@ -146,7 +150,11 @@ class LanguageStatsListener( event: OnProjectActivityEvent, branchIds: MutableSet, ) { - val translationIds = event.modifiedEntities[Translation::class]?.keys.orEmpty() + val translationIds = + event.modifiedEntities[Translation::class] + ?.keys + .orEmpty() + .map { it.id } if (translationIds.isEmpty()) return translationIds.chunked(IN_CLAUSE_BATCH_SIZE).forEach { chunk -> diff --git a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/UserNotificationsTestData.kt b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/UserNotificationsTestData.kt index b795ac74a33..a620eaa363e 100644 --- a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/UserNotificationsTestData.kt +++ b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/UserNotificationsTestData.kt @@ -143,7 +143,7 @@ class UserNotificationsTestData { addKey { name = "some-key" - this@NotificationsTestData.keyCalmProject = this@addKey + this@UserNotificationsTestData.keyCalmProject = this@addKey } addTranslation { @@ -151,7 +151,7 @@ class UserNotificationsTestData { language = en.self text = "Some translation" - this@NotificationsTestData.keyCalmEnTranslation = this@addTranslation + this@UserNotificationsTestData.keyCalmEnTranslation = this@addTranslation } } } @@ -161,7 +161,7 @@ class UserNotificationsTestData { name = "ACME Corporation" slug = "acme" - this@NotificationsTestData.acme = this@addOrganization + this@UserNotificationsTestData.acme = this@addOrganization }.build { addRole { user = orgAdmin @@ -209,7 +209,7 @@ class UserNotificationsTestData { addKey { name = "some-key" - this@NotificationsTestData.keyProject1 = this@addKey + this@UserNotificationsTestData.keyProject1 = this@addKey } addTranslation { @@ -218,7 +218,7 @@ class UserNotificationsTestData { text = "Some translation" state = TranslationState.REVIEWED - this@NotificationsTestData.key1EnTranslation = this@addTranslation + this@UserNotificationsTestData.key1EnTranslation = this@addTranslation } addTranslation { @@ -227,7 +227,7 @@ class UserNotificationsTestData { text = "Some french translation" state = TranslationState.REVIEWED - this@NotificationsTestData.key1FrTranslation = this@addTranslation + this@UserNotificationsTestData.key1FrTranslation = this@addTranslation } addTranslation { @@ -235,7 +235,7 @@ class UserNotificationsTestData { language = cz.self text = "Some czech translation" - this@NotificationsTestData.key1CzTranslation = this@addTranslation + this@UserNotificationsTestData.key1CzTranslation = this@addTranslation } // --- --- --- @@ -309,7 +309,7 @@ class UserNotificationsTestData { addKey { name = "some-key" - this@NotificationsTestData.keyProject2 = this@addKey + this@UserNotificationsTestData.keyProject2 = this@addKey } addTranslation { @@ -317,7 +317,7 @@ class UserNotificationsTestData { language = en.self text = "Some translation" - this@NotificationsTestData.key2EnTranslation = this@addTranslation + this@UserNotificationsTestData.key2EnTranslation = this@addTranslation } addPermission { 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 fe592224f81..51418153e22 100644 --- a/backend/data/src/main/kotlin/io/tolgee/dtos/ComputedPermissionDto.kt +++ b/backend/data/src/main/kotlin/io/tolgee/dtos/ComputedPermissionDto.kt @@ -101,7 +101,7 @@ class ComputedPermissionDto( companion object { fun getEmptyPermission( scopes: Array, - type: ProjectPermissionType?, + type: ProjectPermissionType, ): IPermission { return object : IPermission { override val scopes: Array 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 7ab34a193f8..822c54acbb2 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt @@ -28,8 +28,8 @@ import jakarta.persistence.OrderBy import jakarta.persistence.Transient import jakarta.validation.constraints.NotBlank import org.hibernate.annotations.ColumnDefault -import org.hibernate.annotations.Type import org.hibernate.annotations.SQLRestriction +import org.hibernate.annotations.Type import java.util.Date @Entity 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 194371d1735..ce4eb8caad8 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,7 +23,8 @@ class ActivityDescribingEntity( val entityClass: String, @Id val entityId: Long, -) : Serializable, ActivityEntityWithDescription { +) : Serializable, + ActivityEntityWithDescription { @Column(columnDefinition = "jsonb") @Type(JsonBinaryType::class) var data: Map = mutableMapOf() 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 47c41076e54..3cd7a6325a4 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 @@ -41,7 +41,8 @@ class ActivityModifiedEntity( */ @Id val entityId: Long, -) : Serializable, ActivityEntityWithDescription { +) : Serializable, + ActivityEntityWithDescription { @Column(name = "branch_id") var branchId: Long? = null 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 7d1252e8c1c..b9ffe818bf9 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 @@ -45,7 +45,9 @@ data class UserProjectMetadata( get() = projectNotificationPreferences ?: globalNotificationPreferences } -class UserAccountProjectPermissionsNotificationPreferencesDataView(data: Map) { +class UserAccountProjectPermissionsNotificationPreferencesDataView( + data: Map, +) { init { println(data["permittedViewLanguages"]) } 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 51b99f231cf..68e4c319583 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 @@ -34,23 +34,25 @@ class UserProjectMetadataView( val notificationPreferences = projectNotificationPreferences ?: globalNotificationPreferences val basePermissions = - basePermissions?.let { - println(basePermissions) - Permission.PermissionWithLanguageIdsWrapper( - basePermissions, - fetchedBaseViewLanguages, - null, - null, - ) - }?.permission + basePermissions + ?.let { + println(basePermissions) + Permission.PermissionWithLanguageIdsWrapper( + basePermissions, + fetchedBaseViewLanguages, + null, + null, + ) + }?.permission val permissions = - permissions?.let { - Permission.PermissionWithLanguageIdsWrapper( - permissions, - fetchedViewLanguages, - null, - null, - ) - }?.permission + permissions + ?.let { + Permission.PermissionWithLanguageIdsWrapper( + permissions, + fetchedViewLanguages, + null, + null, + ) + }?.permission } 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 031cd92ebf9..cc3ebb81f67 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt @@ -33,7 +33,8 @@ class NotificationPreferencesService( private val securityService: SecurityService, ) { fun getAllPreferences(user: Long): Map { - return notificationPreferencesRepository.findAllByUserAccountId(user) + return notificationPreferencesRepository + .findAllByUserAccountId(user) .associate { val key = it.project?.id?.toString() ?: "global" val dto = NotificationPreferencesDto.fromEntity(it) 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 b3e7fa399c9..a29a57383f2 100644 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationDebouncer.kt +++ b/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationDebouncer.kt @@ -25,7 +25,7 @@ import io.tolgee.notifications.dto.NotificationCreateDto import io.tolgee.notifications.dto.UserNotificationParamsDto import io.tolgee.repository.notifications.UserNotificationRepository import org.springframework.stereotype.Component -import java.util.* +import java.util.EnumSet typealias UserNotificationDebounceResult = Pair, List> @@ -115,8 +115,11 @@ class UserNotificationDebouncer( entities: List?, ): List { val keyId = - entities?.find { it.entityClass == Translation::class.simpleName } - ?.describingRelations?.get("key")?.entityId ?: 0L + entities + ?.find { it.entityClass == Translation::class.simpleName } + ?.describingRelations + ?.get("key") + ?.entityId ?: 0L return userNotificationRepository.findCandidatesForTranslationUpdateNotificationDebouncing( type, @@ -132,8 +135,11 @@ class UserNotificationDebouncer( entities: List?, ): List { val translationId = - entities?.find { it.entityClass == TranslationComment::class.simpleName } - ?.describingRelations?.get("translation")?.entityId ?: 0L + entities + ?.find { it.entityClass == TranslationComment::class.simpleName } + ?.describingRelations + ?.get("translation") + ?.entityId ?: 0L return userNotificationRepository.findCandidatesForCommentNotificationDebouncing( 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 4d8f31ba9d2..6debf739d44 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 @@ -64,7 +64,8 @@ class UserNotificationDispatch( private fun handleActivityNotification(e: NotificationCreateEvent) { val users = - userAccountService.getAllConnectedUserProjectMetadataViews(e.notification.projectId) + userAccountService + .getAllConnectedUserProjectMetadataViews(e.notification.projectId) .filter { it.notificationPreferences?.disabledNotifications?.contains(e.notification.type) != true && it.userAccountId != e.responsibleUserId 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 64b4905a424..16257e645eb 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 @@ -113,6 +113,63 @@ class ActivityEventListener( // so it causes a compile error when new activities are added // and ensures the notification policy is adjusted accordingly. ActivityType.UNKNOWN, + ActivityType.KEY_CHARACTER_LIMIT_EDIT, + ActivityType.KEY_SOFT_DELETE, + ActivityType.KEY_RESTORE, + ActivityType.KEY_HARD_DELETE, + ActivityType.BATCH_KEY_RESTORE, + ActivityType.BATCH_KEY_HARD_DELETE, + ActivityType.BATCH_ASSIGN_TRANSLATION_LABEL, + ActivityType.BATCH_UNASSIGN_TRANSLATION_LABEL, + ActivityType.TASKS_CREATE, + ActivityType.TASK_CREATE, + ActivityType.TASK_UPDATE, + ActivityType.TASK_KEYS_UPDATE, + ActivityType.TASK_FINISH, + ActivityType.TASK_CLOSE, + ActivityType.TASK_REOPEN, + ActivityType.TASK_KEY_UPDATE, + ActivityType.ORDER_TRANSLATION, + ActivityType.GLOSSARY_CREATE, + ActivityType.GLOSSARY_UPDATE, + ActivityType.GLOSSARY_DELETE, + ActivityType.GLOSSARY_IMPORT, + ActivityType.GLOSSARY_TERM_CREATE, + ActivityType.GLOSSARY_TERM_UPDATE, + ActivityType.GLOSSARY_TERM_DELETE, + ActivityType.GLOSSARY_TERM_TRANSLATION_UPDATE, + ActivityType.TRANSLATION_MEMORY_CREATE, + ActivityType.TRANSLATION_MEMORY_UPDATE, + ActivityType.TRANSLATION_MEMORY_DELETE, + ActivityType.TRANSLATION_MEMORY_ASSIGN_PROJECT, + ActivityType.TRANSLATION_MEMORY_UNASSIGN_PROJECT, + ActivityType.TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG, + ActivityType.TRANSLATION_MEMORY_ENTRY_CREATE, + ActivityType.TRANSLATION_MEMORY_ENTRY_UPDATE, + ActivityType.TRANSLATION_MEMORY_ENTRY_DELETE, + ActivityType.TRANSLATION_MEMORY_IMPORT, + ActivityType.TRANSLATION_MEMORY_COPY_FROM_PROJECT, + ActivityType.TRANSLATION_LABELS_EDIT, + ActivityType.TRANSLATION_LABEL_ASSIGN, + ActivityType.TRANSLATION_LABEL_CREATE, + ActivityType.TRANSLATION_LABEL_UPDATE, + ActivityType.TRANSLATION_LABEL_DELETE, + ActivityType.CREATE_SUGGESTION, + ActivityType.DECLINE_SUGGESTION, + ActivityType.ACCEPT_SUGGESTION, + ActivityType.REVERSE_SUGGESTION, + ActivityType.DELETE_SUGGESTION, + ActivityType.SUGGESTION_SET_ACTIVE, + ActivityType.AI_PROMPT_CREATE, + ActivityType.AI_PROMPT_UPDATE, + ActivityType.AI_PROMPT_DELETE, + ActivityType.BRANCH_CREATE, + ActivityType.BRANCH_RENAME, + ActivityType.BRANCH_DELETE, + ActivityType.BRANCH_PROTECTION_CHANGE, + ActivityType.BRANCH_MERGE, + ActivityType.QA_ISSUE_IGNORE, + ActivityType.QA_ISSUE_UNIGNORE, ActivityType.DISMISS_AUTO_TRANSLATED_STATE, ActivityType.TRANSLATION_COMMENT_DELETE, ActivityType.TRANSLATION_COMMENT_EDIT, 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 be85de420f7..3f846fa99ae 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 @@ -41,12 +41,13 @@ class BatchJobListener( e.job.projectId, ) + val projectId = e.job.projectId ?: return val job = entityManager.getReference(BatchJob::class.java, e.job.id) applicationEventPublisher.publishEvent( NotificationCreateEvent( NotificationCreateDto( type = NotificationType.BATCH_JOB_ERRORED, - projectId = e.job.projectId, + projectId = projectId, batchJob = job, ), source = e, 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 9246cc2d9be..7063cb72367 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/CachedPermissionService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/CachedPermissionService.kt @@ -52,7 +52,8 @@ class CachedPermissionService( projectId = projectId, userId = userId, organizationId = organizationId, - )?.permission?.let { permission -> + )?.permission + ?.let { permission -> PermissionDto( id = permission.id, userId = permission.user?.id, diff --git a/backend/data/src/main/kotlin/io/tolgee/service/project/ProjectHardDeletingService.kt b/backend/data/src/main/kotlin/io/tolgee/service/project/ProjectHardDeletingService.kt index 48d09db840c..52c64fb6856 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/project/ProjectHardDeletingService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/project/ProjectHardDeletingService.kt @@ -5,6 +5,8 @@ import io.tolgee.constants.Caches import io.tolgee.dtos.cacheable.ProjectDto import io.tolgee.events.OnProjectSoftDeleted import io.tolgee.model.Project +import io.tolgee.notifications.NotificationPreferencesService +import io.tolgee.notifications.UserNotificationService import io.tolgee.repository.ProjectRepository import io.tolgee.repository.qa.ProjectQaConfigRepository import io.tolgee.security.ProjectHolder @@ -22,8 +24,6 @@ import io.tolgee.service.key.ScreenshotService import io.tolgee.service.label.LabelService import io.tolgee.service.language.LanguageService import io.tolgee.service.machineTranslation.MtServiceConfigService -import io.tolgee.notifications.NotificationPreferencesService -import io.tolgee.notifications.UserNotificationService import io.tolgee.service.security.ApiKeyService import io.tolgee.service.security.PermissionService import io.tolgee.service.translationMemory.TranslationMemoryManagementService 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 0396379e538..2a55f83727e 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 @@ -69,11 +69,12 @@ class PermissionService( userId: Long? = null, organizationId: Long? = null, ): Permission? { - return permissionRepository.findOneByProjectIdAndUserIdAndOrganizationId( - projectId = projectId, - userId = userId, - organizationId = organizationId, - ) + return permissionRepository + .findOneByProjectIdAndUserIdAndOrganizationId( + projectId = projectId, + userId = userId, + organizationId = organizationId, + )?.permission } @Transactional(readOnly = true) @@ -238,7 +239,8 @@ class PermissionService( when { organizationRole == OrganizationRoleType.OWNER -> ComputedPermissionDto.ORGANIZATION_OWNER directPermission != null -> ComputedPermissionDto(directPermission, ComputedPermissionOrigin.DIRECT) - organizationRole == OrganizationRoleType.MEMBER || organizationRole == OrganizationRoleType.MAINTAINER -> + (organizationRole == OrganizationRoleType.MEMBER || organizationRole == OrganizationRoleType.MAINTAINER) && + organizationBasePermission != null -> ComputedPermissionDto( organizationBasePermission, ComputedPermissionOrigin.ORGANIZATION_BASE, 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 7e4792c0de3..4f2a553a54e 100644 --- a/backend/data/src/main/kotlin/io/tolgee/util/dateExt.kt +++ b/backend/data/src/main/kotlin/io/tolgee/util/dateExt.kt @@ -25,12 +25,6 @@ private fun Date.addToCalendar( 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 diff --git a/ee/backend/app/src/main/kotlin/io/tolgee/ee/component/qa/QaActivityListener.kt b/ee/backend/app/src/main/kotlin/io/tolgee/ee/component/qa/QaActivityListener.kt index 5bce8c3333c..30dcb858dd1 100644 --- a/ee/backend/app/src/main/kotlin/io/tolgee/ee/component/qa/QaActivityListener.kt +++ b/ee/backend/app/src/main/kotlin/io/tolgee/ee/component/qa/QaActivityListener.kt @@ -306,7 +306,7 @@ class QaActivityListener( val languageEntities = event.modifiedEntities[Language::class] ?: return emptyList() return languageEntities .filter { (_, entity) -> entity.modifications.containsKey("tag") } - .map { (id, _) -> id } + .map { (language, _) -> language.id } } // endregion From 348710d43990ef06b7131686be988c05293c6779 Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Sat, 11 Jul 2026 15:03:03 +0200 Subject: [PATCH 46/57] refactor: drop branch user-notification system in favor of main's notifications MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Main shipped its own in-app notification system (Notification entity, settings, email channel, top-bar popup) while this branch was dormant. Remove the branch's parallel UserNotification/NotificationPreferences stack — entities, services, dispatch/debounce, REST controllers, test data, webapp views and DB changesets. Activity grouping stays. --- .../v2/controllers/InitialDataController.kt | 3 - .../NotificationPreferencesController.kt | 128 ------ .../notifications/NotificationsController.kt | 122 ------ .../hateoas/initialData/InitialDataModel.kt | 1 - .../notifications/UserNotificationModel.kt | 38 -- .../UserNotificationModelAssembler.kt | 71 --- .../notifications/AbstractNotificationTest.kt | 102 ----- .../RemappedNotificationsTest.kt | 225 ---------- .../UserNotificationDebounceTest.kt | 129 ------ .../UserNotificationDispatchTest.kt | 224 ---------- .../UserNotificationSubscriptionTest.kt | 68 --- .../UserNotificationTranslationTest.kt | 118 ----- .../testDataBuilder/TestDataService.kt | 10 - .../NotificationPreferencesBuilder.kt | 11 - .../builders/UserAccountBuilder.kt | 4 - .../data/NotificationSubscriptionTestData.kt | 109 ----- .../data/UserNotificationsTestData.kt | 331 -------------- .../kotlin/io/tolgee/model/UserAccount.kt | 17 - .../notifications/NotificationPreferences.kt | 68 --- .../model/notifications/UserNotification.kt | 81 ---- ...missionsNotificationPreferencesDataView.kt | 80 ---- .../model/views/UserProjectMetadataView.kt | 58 --- .../NotificationPreferencesService.kt | 139 ------ .../notifications/NotificationStatus.kt | 23 - .../tolgee/notifications/NotificationType.kt | 58 --- .../UserNotificationDebouncer.kt | 164 ------- .../notifications/UserNotificationService.kt | 141 ------ .../dispatchers/UserNotificationDispatch.kt | 159 ------- .../dto/NotificationCreateDto.kt | 63 --- .../dto/NotificationPreferencesDto.kt | 38 -- .../dto/UserNotificationParamsDto.kt | 25 -- .../events/NotificationCreateEvent.kt | 25 -- .../events/UserNotificationPushEvent.kt | 27 -- .../listeners/ActivityEventListener.kt | 414 ------------------ .../listeners/BatchJobListener.kt | 58 --- .../repository/UserAccountRepository.kt | 40 -- .../NotificationPreferencesRepository.kt | 46 -- .../UserNotificationRepository.kt | 171 -------- .../project/ProjectHardDeletingService.kt | 8 - .../tolgee/service/project/ProjectService.kt | 2 - .../service/security/PermissionService.kt | 9 - .../service/security/UserAccountService.kt | 12 - .../main/resources/db/changelog/schema.xml | 90 ---- .../e2eData/NotificationsE2eDataController.kt | 55 --- .../layout/TopBar/NotificationBell.tsx | 62 --- webapp/src/constants/links.tsx | 7 - .../notifications/NotificationsRouter.tsx | 64 --- .../views/notifications/NotificationsView.tsx | 63 --- 48 files changed, 3961 deletions(-) delete mode 100644 backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationPreferencesController.kt delete mode 100644 backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationsController.kt delete mode 100644 backend/api/src/main/kotlin/io/tolgee/hateoas/notifications/UserNotificationModel.kt delete mode 100644 backend/api/src/main/kotlin/io/tolgee/hateoas/notifications/UserNotificationModelAssembler.kt delete mode 100644 backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt delete mode 100644 backend/app/src/test/kotlin/io/tolgee/notifications/RemappedNotificationsTest.kt delete mode 100644 backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt delete mode 100644 backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDispatchTest.kt delete mode 100644 backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationSubscriptionTest.kt delete mode 100644 backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationTranslationTest.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/NotificationPreferencesBuilder.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationSubscriptionTestData.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/UserNotificationsTestData.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/model/notifications/NotificationPreferences.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/model/notifications/UserNotification.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionsNotificationPreferencesDataView.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/model/views/UserProjectMetadataView.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/NotificationStatus.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/NotificationType.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationDebouncer.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationPreferencesDto.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/dto/UserNotificationParamsDto.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationCreateEvent.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/events/UserNotificationPushEvent.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/repository/notifications/NotificationPreferencesRepository.kt delete mode 100644 backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt delete mode 100644 backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/NotificationsE2eDataController.kt delete mode 100644 webapp/src/component/layout/TopBar/NotificationBell.tsx delete mode 100644 webapp/src/views/notifications/NotificationsRouter.tsx delete mode 100644 webapp/src/views/notifications/NotificationsView.tsx 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 e1df77e3ac8..5d6fea6bd4f 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 @@ -10,7 +10,6 @@ import io.tolgee.hateoas.initialData.InitialDataModel import io.tolgee.hateoas.qa.QaCheckCategoryModelAssembler import io.tolgee.hateoas.sso.PublicSsoTenantModelAssembler import io.tolgee.hateoas.userAccount.PrivateUserAccountModelAssembler -import io.tolgee.notifications.UserNotificationService import io.tolgee.openApiDocs.OpenApiHideFromPublicDocs import io.tolgee.security.authentication.AuthenticationFacade import io.tolgee.service.TenantService @@ -35,7 +34,6 @@ class InitialDataController( private val userPreferencesService: UserPreferencesService, private val preferredOrganizationFacade: PreferredOrganizationFacade, private val announcementController: AnnouncementController, - private val userNotificationService: UserNotificationService, private val tenantService: TenantService, private val authInfoModelAssembler: AuthInfoModelAssembler, private val privateUserAccountModelAssembler: PrivateUserAccountModelAssembler, @@ -62,7 +60,6 @@ class InitialDataController( data.preferredOrganization = preferredOrganizationFacade.getPreferred() data.languageTag = userPreferencesService.find(userAccount.id)?.language data.announcement = announcementController.getLatest() - data.unreadNotifications = userNotificationService.getUnreadNotificationsCount(userAccount.id) data.eeSubscription = getEeSubscriptionModel() } 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 deleted file mode 100644 index 53c75fe6ff5..00000000000 --- a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationPreferencesController.kt +++ /dev/null @@ -1,128 +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.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 deleted file mode 100644 index 426f6518358..00000000000 --- a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationsController.kt +++ /dev/null @@ -1,122 +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.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.core.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/initialData/InitialDataModel.kt b/backend/api/src/main/kotlin/io/tolgee/hateoas/initialData/InitialDataModel.kt index b00253523d7..51241ba636a 100644 --- a/backend/api/src/main/kotlin/io/tolgee/hateoas/initialData/InitialDataModel.kt +++ b/backend/api/src/main/kotlin/io/tolgee/hateoas/initialData/InitialDataModel.kt @@ -18,5 +18,4 @@ class InitialDataModel( var announcement: AnnouncementDto? = null, var eeSubscription: InitialDataEeSubscriptionModel? = null, var qaCheckCategories: List? = 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 deleted file mode 100644 index 57d3595fe85..00000000000 --- a/backend/api/src/main/kotlin/io/tolgee/hateoas/notifications/UserNotificationModel.kt +++ /dev/null @@ -1,38 +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.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.Date - -@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 deleted file mode 100644 index 1502f11f101..00000000000 --- a/backend/api/src/main/kotlin/io/tolgee/hateoas/notifications/UserNotificationModelAssembler.kt +++ /dev/null @@ -1,71 +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.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/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt deleted file mode 100644 index 67714651cfb..00000000000 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt +++ /dev/null @@ -1,102 +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.repository.notifications.UserNotificationRepository -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 userNotificationService: UserNotificationService - - @Autowired - lateinit var taskScheduler: TaskScheduler - - @SpyBean - @Autowired - lateinit var userNotificationRepository: UserNotificationRepository - - lateinit var semaphore: Semaphore - - @BeforeEach - fun setupTests() { - semaphore = Semaphore(0) - - doAnswer { - entityManager.persist(it.arguments[0]) - entityManager.flush() - - // 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).toInstant(), - ) - - it.arguments[0] - }.`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).toInstant(), - ) - - it.arguments[0] - }.`when`(userNotificationRepository).saveAll(Mockito.anyList()) - } - - @AfterEach - fun clearWatcher() { - Mockito.reset(userNotificationRepository) - } - - fun waitUntilUserNotificationDispatch(count: Int = 1) { - 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(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 deleted file mode 100644 index 963d7c3da3c..00000000000 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/RemappedNotificationsTest.kt +++ /dev/null @@ -1,225 +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.UserNotificationsTestData -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.fixtures.generateImage -import io.tolgee.testing.assert -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.springframework.mock.web.MockMultipartFile - -class RemappedNotificationsTest : AbstractNotificationTest() { - lateinit var testData: UserNotificationsTestData - - @BeforeEach - override fun setupTests() { - testData = UserNotificationsTestData() - testDataService.saveTestData(testData.root) - - super.setupTests() - } - - @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(12) - 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(1) - germanTranslatorNotifications.assert.hasSize(1) - frenchCzechTranslatorNotifications.assert.hasSize(2) - bobNotifications.assert.hasSize(2) - - 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() - } - - @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() } - - 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(25) - val acmeChiefNotifications = userNotificationRepository.findAllByRecipient(testData.orgAdmin) - val czechTranslatorNotifications = userNotificationRepository.findAllByRecipient(testData.czechTranslator) - val bobNotifications = userNotificationRepository.findAllByRecipient(testData.bob) - - bobNotifications.assert - .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) - .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/UserNotificationDebounceTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt deleted file mode 100644 index de4093696eb..00000000000 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt +++ /dev/null @@ -1,129 +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.UserNotificationsTestData -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 -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: UserNotificationsTestData - - @BeforeEach - override fun setupTests() { - testData = UserNotificationsTestData() - testDataService.saveTestData(testData.root) - - super.setupTests() - } - - @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) - - performAuthPost( - url = "/v2/projects/${testData.calmProject.id}/languages", - content = - LanguageRequest( - name = "Meow", - originalName = "meow", - tag = "meow-en", - ), - ).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 deleted file mode 100644 index 5f2ee1fc24d..00000000000 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDispatchTest.kt +++ /dev/null @@ -1,224 +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.UserNotificationsTestData -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.fixtures.generateImage -import io.tolgee.testing.assert -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.springframework.mock.web.MockMultipartFile - -class UserNotificationDispatchTest : AbstractNotificationTest() { - lateinit var testData: UserNotificationsTestData - - @BeforeEach - override fun setupTests() { - testData = UserNotificationsTestData() - testDataService.saveTestData(testData.root) - - super.setupTests() - } - - @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/app/src/test/kotlin/io/tolgee/notifications/UserNotificationSubscriptionTest.kt b/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationSubscriptionTest.kt deleted file mode 100644 index 31c18c34e29..00000000000 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationSubscriptionTest.kt +++ /dev/null @@ -1,68 +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.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 deleted file mode 100644 index b062263b611..00000000000 --- a/backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationTranslationTest.kt +++ /dev/null @@ -1,118 +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.UserNotificationsTestData -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: UserNotificationsTestData - - @BeforeEach - override fun setupTests() { - testData = UserNotificationsTestData() - testDataService.saveTestData(testData.root) - - super.setupTests() - } - - @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() - - 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 } - .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 039756ca53e..82e5a1b4790 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 @@ -137,7 +137,6 @@ class TestDataService( ensureProjectTms(builder) saveTranslationMemoryData(builder) saveNotifications(builder) - saveNotificationPreferences(builder) finalize() } @@ -160,15 +159,6 @@ class TestDataService( } } - private fun saveNotificationPreferences(builder: TestDataBuilder) { - // 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) - } - } - } - @Transactional fun cleanTestData(builder: TestDataBuilder) { runBeforeCleanMethodsOfAdditionalSavers(builder) 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 deleted file mode 100644 index d9281301aaf..00000000000 --- a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/NotificationPreferencesBuilder.kt +++ /dev/null @@ -1,11 +0,0 @@ -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 4c7af304004..214dbd3ca76 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 @@ -7,7 +7,6 @@ import io.tolgee.model.Pat import io.tolgee.model.UserAccount import io.tolgee.model.UserPreferences import io.tolgee.model.notifications.Notification -import io.tolgee.model.notifications.NotificationPreferences import io.tolgee.model.slackIntegration.SlackUserConnection import org.springframework.core.io.ClassPathResource @@ -24,7 +23,6 @@ class UserAccountBuilder( var authProviderChangeRequest: AuthProviderChangeRequestBuilder? = null var pats: MutableList = mutableListOf() var slackUserConnections: MutableList = mutableListOf() - var notificationPreferences: MutableList = mutableListOf() var notifications: MutableList = mutableListOf() } @@ -51,7 +49,5 @@ class UserAccountBuilder( fun addSlackUserConnection(ft: FT) = addOperation(data.slackUserConnections, ft) - fun addNotificationPreferences(ft: FT) = addOperation(data.notificationPreferences, ft) - fun addNotification(ft: FT) = addOperation(data.notifications, 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 deleted file mode 100644 index 5210ae83077..00000000000 --- a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationSubscriptionTestData.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.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/development/testDataBuilder/data/UserNotificationsTestData.kt b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/UserNotificationsTestData.kt deleted file mode 100644 index a620eaa363e..00000000000 --- a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/UserNotificationsTestData.kt +++ /dev/null @@ -1,331 +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.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 -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 UserNotificationsTestData { - 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 calmProject: Project // A project with only Alice in it for less notification noise - - lateinit var keyProject1: Key - lateinit var key1EnTranslation: Translation - lateinit var key1FrTranslation: Translation - lateinit var key1CzTranslation: Translation - - 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 { - 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 - }.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@UserNotificationsTestData.keyCalmProject = this@addKey - } - - addTranslation { - this.key = key.self - language = en.self - text = "Some translation" - - this@UserNotificationsTestData.keyCalmEnTranslation = this@addTranslation - } - } - } - } - - addOrganization { - name = "ACME Corporation" - slug = "acme" - - this@UserNotificationsTestData.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@UserNotificationsTestData.keyProject1 = this@addKey - } - - addTranslation { - this.key = key.self - language = en.self - text = "Some translation" - state = TranslationState.REVIEWED - - this@UserNotificationsTestData.key1EnTranslation = this@addTranslation - } - - addTranslation { - this.key = key.self - language = fr.self - text = "Some french translation" - state = TranslationState.REVIEWED - - this@UserNotificationsTestData.key1FrTranslation = this@addTranslation - } - - addTranslation { - this.key = key.self - language = cz.self - text = "Some czech translation" - - this@UserNotificationsTestData.key1CzTranslation = this@addTranslation - } - - // --- --- --- - addPermission { - user = projectManager - type = ProjectPermissionType.MANAGE - } - - addPermission { - user = frenchTranslator - type = ProjectPermissionType.EDIT - 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 - type = ProjectPermissionType.EDIT - 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 - type = ProjectPermissionType.EDIT - 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 - type = ProjectPermissionType.EDIT - 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@UserNotificationsTestData.keyProject2 = this@addKey - } - - addTranslation { - this.key = key.self - language = en.self - text = "Some translation" - - this@UserNotificationsTestData.key2EnTranslation = this@addTranslation - } - - addPermission { - user = alice - scopes = arrayOf(Scope.TRANSLATIONS_EDIT, Scope.SCREENSHOTS_UPLOAD) - } - } - } - } - } -} 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 822c54acbb2..439f9a7e823 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt @@ -6,8 +6,6 @@ import io.tolgee.api.IUserAccount import io.tolgee.api.SimpleUserAccount import io.tolgee.component.ThirdPartyAuthTypeConverter import io.tolgee.model.enums.ThirdPartyAuthType -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 io.tolgee.model.task.Task @@ -28,7 +26,6 @@ import jakarta.persistence.OrderBy import jakarta.persistence.Transient import jakarta.validation.constraints.NotBlank import org.hibernate.annotations.ColumnDefault -import org.hibernate.annotations.SQLRestriction import org.hibernate.annotations.Type import java.util.Date @@ -149,17 +146,6 @@ data class UserAccount( @OneToMany(mappedBy = "userAccount", fetch = FetchType.LAZY, orphanRemoval = true) var slackConfig: MutableList = mutableListOf() - @OneToMany(fetch = FetchType.LAZY, cascade = [CascadeType.REMOVE], orphanRemoval = true, mappedBy = "recipient") - var userNotifications: MutableList = mutableListOf() - - @SQLRestriction("project_id IS NOT NULL") - @OneToMany(fetch = FetchType.LAZY, cascade = [CascadeType.REMOVE], orphanRemoval = true, mappedBy = "userAccount") - var projectNotificationPreferences: MutableList = mutableListOf() - - @SQLRestriction("project_id IS NULL") - @OneToMany(fetch = FetchType.LAZY, cascade = [CascadeType.REMOVE], orphanRemoval = true, mappedBy = "userAccount") - private var _globalNotificationPreferences: MutableList = mutableListOf() - override val deleted: Boolean get() = deletedAt != null @@ -186,9 +172,6 @@ data class UserAccount( this.resetPasswordCode = resetPasswordCode } - val globalNotificationPreferences: NotificationPreferences? - get() = _globalNotificationPreferences.firstOrNull() - enum class Role { USER, ADMIN, 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 deleted file mode 100644 index 4770be57177..00000000000 --- a/backend/data/src/main/kotlin/io/tolgee/model/notifications/NotificationPreferences.kt +++ /dev/null @@ -1,68 +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.model.notifications - -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 - -@Entity -@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( - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(nullable = false) - val userAccount: UserAccount, - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(nullable = true) - var project: Project?, - @Type(EnumArrayType::class, parameters = [Parameter(name = EnumArrayType.SQL_ARRAY_TYPE, value = "varchar")]) - @Column(nullable = false, columnDefinition = "varchar[]") - var disabledNotifications: Array, -) { - @Id - @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 deleted file mode 100644 index 7e531c5c7a9..00000000000 --- a/backend/data/src/main/kotlin/io/tolgee/model/notifications/UserNotification.kt +++ /dev/null @@ -1,81 +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.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 -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.* - -@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, -) { - @Id - @SequenceGenerator(name = "notification_seq", sequenceName = "sequence_notifications") - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "notification_seq") - val id: Long = 0 - - @Column(nullable = false) - @ColumnDefault("true") - var unread: Boolean = true - - @Temporal(TemporalType.TIMESTAMP) - var markedDoneAt: Date? = null - - @OrderBy - @UpdateTimestamp - @Temporal(TemporalType.TIMESTAMP) - val lastUpdated: Date = Date() -} 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 deleted file mode 100644 index b9ffe818bf9..00000000000 --- a/backend/data/src/main/kotlin/io/tolgee/model/views/UserAccountProjectPermissionsNotificationPreferencesDataView.kt +++ /dev/null @@ -1,80 +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.model.views - -import io.tolgee.model.OrganizationRole -import io.tolgee.model.Permission -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 - -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?, -) { - 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 deleted file mode 100644 index 68e4c319583..00000000000 --- a/backend/data/src/main/kotlin/io/tolgee/model/views/UserProjectMetadataView.kt +++ /dev/null @@ -1,58 +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.model.views - -import io.tolgee.model.Permission -import io.tolgee.model.enums.OrganizationRoleType -import io.tolgee.model.notifications.NotificationPreferences - -class UserProjectMetadataView( - val userAccountId: Long, - val projectId: Long, - val organizationRole: OrganizationRoleType?, - basePermissions: Permission?, - fetchedBaseViewLanguages: Any?, - permissions: Permission?, - fetchedViewLanguages: Any?, - globalNotificationPreferences: NotificationPreferences?, - projectNotificationPreferences: NotificationPreferences?, -) { - val notificationPreferences = projectNotificationPreferences ?: globalNotificationPreferences - - val basePermissions = - basePermissions - ?.let { - println(basePermissions) - 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/notifications/NotificationPreferencesService.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt deleted file mode 100644 index cc3ebb81f67..00000000000 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationPreferencesService.kt +++ /dev/null @@ -1,139 +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.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 jakarta.persistence.EntityManager -import org.springframework.stereotype.Service - -@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.getProjectPermissionScopesNoApiKey(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.getProjectPermissionScopesNoApiKey(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) - } - - fun deleteAllByProjectId(projectId: Long) { - notificationPreferencesRepository.deleteAllByProjectId(projectId) - } -} diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationStatus.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationStatus.kt deleted file mode 100644 index d80da10164a..00000000000 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationStatus.kt +++ /dev/null @@ -1,23 +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 - -enum class NotificationStatus { - 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 deleted file mode 100644 index cf66b8fffca..00000000000 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/NotificationType.kt +++ /dev/null @@ -1,58 +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 java.util.* - -enum class NotificationType { - 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, - ; - - 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 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 deleted file mode 100644 index a29a57383f2..00000000000 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationDebouncer.kt +++ /dev/null @@ -1,164 +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.UserAccount -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.notifications.UserNotificationRepository -import org.springframework.stereotype.Component -import java.util.EnumSet - -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 { - 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, - projectId: Long, - recipients: List, - entities: List?, - ): List { - val keyId = - entities - ?.find { it.entityClass == Translation::class.simpleName } - ?.describingRelations - ?.get("key") - ?.entityId ?: 0L - - return userNotificationRepository.findCandidatesForTranslationUpdateNotificationDebouncing( - type, - projectId, - recipients, - keyId, - ) - } - - private fun findCandidatesForCommentNotificationDebouncing( - projectId: Long, - recipients: List, - entities: List?, - ): List { - val translationId = - entities - ?.find { it.entityClass == TranslationComment::class.simpleName } - ?.describingRelations - ?.get("translation") - ?.entityId ?: 0L - - return userNotificationRepository.findCandidatesForCommentNotificationDebouncing( - 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, - ) - } -} diff --git a/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt deleted file mode 100644 index 976439015ed..00000000000 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/UserNotificationService.kt +++ /dev/null @@ -1,141 +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.notifications.UserNotification -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 -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, - ) { - return dispatchNotifications(notificationDto, listOf(params)) - } - - @Transactional - fun dispatchNotifications( - notificationDto: NotificationCreateDto, - params: List, - ) { - val createdUserNotificationObjects = mutableSetOf() - val updatedUserNotificationObjects = mutableSetOf() - - val (processed, remaining) = userNotificationDebouncer.debounce(notificationDto, params) - updatedUserNotificationObjects.addAll( - userNotificationRepository.saveAll(processed), - ) - - remaining.forEach { - val notification = notificationDto.toUserNotificationEntity(it, entityManager) - createdUserNotificationObjects.add( - userNotificationRepository.save(notification), - ) - } - - // Dispatch event - applicationEventPublisher.publishEvent( - UserNotificationPushEvent( - createdUserNotificationObjects, - updatedUserNotificationObjects, - ), - ) - } - - fun findNotificationsOfUserFilteredPaged( - user: Long, - status: Set, - pageable: Pageable, - ): List { - 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/notifications/dispatchers/UserNotificationDispatch.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt deleted file mode 100644 index 6debf739d44..00000000000 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dispatchers/UserNotificationDispatch.kt +++ /dev/null @@ -1,159 +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.dispatchers - -import io.tolgee.dtos.ComputedPermissionDto -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.UserProjectMetadataView -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.language.LanguageService -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 - -@Component -@EnableAsync(proxyTargetClass = true) -class UserNotificationDispatch( - private val userAccountService: UserAccountService, - private val permissionService: PermissionService, - private val languageService: LanguageService, - private val userNotificationService: UserNotificationService, - private val entityManager: EntityManager, -) : Logging { - @Async - @EventListener - fun onNotificationCreate(e: NotificationCreateEvent) { - logger.trace("Received notification creation event {}", e) - - when { - 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) { - 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 notifications = - users.mapNotNull { - handleActivityNotificationForUser(e, translationToLanguageMap, it) - } - - userNotificationService.dispatchNotifications(e.notification, notifications) - } - - private fun handleBatchJobNotification(e: NotificationCreateEvent) { - // Only send a full notification for job failures. - if (e.notification.type != NotificationType.BATCH_JOB_ERRORED) return - - val batchJob = e.notification.batchJob!! - val author = batchJob.author ?: return - userNotificationService.dispatchNotification( - e.notification, - UserNotificationParamsDto(author), - ) - } - - private fun handleActivityNotificationForUser( - e: NotificationCreateEvent, - translationToLanguageMap: Map, - userProjectMetadataView: UserProjectMetadataView, - ): UserNotificationParamsDto? { - 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, - translationToLanguageMap, - ) - - if (filteredModifiedEntities.isEmpty()) return null - - return UserNotificationParamsDto( - recipient = entityManager.getReference(UserAccount::class.java, userProjectMetadataView.userAccountId), - modifiedEntities = filteredModifiedEntities.toSet(), - ) - } - - private fun filterModifiedEntities( - modifiedEntities: List, - permissions: ComputedPermissionDto, - translationToLanguageMap: Map, - ): Set { - return modifiedEntities - .filter { - when (it.entityClass) { - Screenshot::class.simpleName -> - isUserAllowedToSeeScreenshot(permissions) - Translation::class.simpleName -> - isUserAllowedToSeeTranslation(it, permissions, translationToLanguageMap) - else -> true - } - }.toSet() - } - - private fun isUserAllowedToSeeScreenshot(permissions: ComputedPermissionDto): Boolean { - return permissions.expandedScopes.contains(Scope.SCREENSHOTS_VIEW) - } - - private fun isUserAllowedToSeeTranslation( - entity: ActivityModifiedEntity, - permissions: ComputedPermissionDto, - translationToLanguageMap: Map, - ): Boolean { - if (!permissions.expandedScopes.contains(Scope.TRANSLATIONS_VIEW)) return false - - val language = translationToLanguageMap[entity.entityId] ?: return 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 deleted file mode 100644 index 96e4745a59c..00000000000 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationCreateDto.kt +++ /dev/null @@ -1,63 +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.dto - -import io.tolgee.model.Project -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 projectId: Long, - val modifiedEntities: MutableList? = null, - val batchJob: BatchJob? = null, -) { - fun toUserNotificationEntity( - params: UserNotificationParamsDto, - em: EntityManager, - ): UserNotification { - return UserNotification( - type = type, - recipient = params.recipient, - project = em.getReference(Project::class.java, projectId), - modifiedEntities = params.modifiedEntities.toMutableList(), - ) - } - - fun mergeIntoUserNotificationEntity( - userNotification: UserNotification, - params: UserNotificationParamsDto, - ) { - when { - NotificationType.ACTIVITY_NOTIFICATIONS.contains(userNotification.type) -> - mergeIntoNotificationEntityActivity(userNotification, params) - - else -> - throw IllegalArgumentException("Cannot merge notifications of type ${userNotification.type}") - } - } - - private fun mergeIntoNotificationEntityActivity( - userNotification: UserNotification, - params: UserNotificationParamsDto, - ) { - userNotification.modifiedEntities.addAll(params.modifiedEntities) - } -} 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 deleted file mode 100644 index 6b1051d5c64..00000000000 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/NotificationPreferencesDto.kt +++ /dev/null @@ -1,38 +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.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/dto/UserNotificationParamsDto.kt b/backend/data/src/main/kotlin/io/tolgee/notifications/dto/UserNotificationParamsDto.kt deleted file mode 100644 index 56375260466..00000000000 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/dto/UserNotificationParamsDto.kt +++ /dev/null @@ -1,25 +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.dto - -import io.tolgee.model.UserAccount -import io.tolgee.model.activity.ActivityModifiedEntity - -data class UserNotificationParamsDto( - val recipient: UserAccount, - 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 deleted file mode 100644 index ecb68749731..00000000000 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/events/NotificationCreateEvent.kt +++ /dev/null @@ -1,25 +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.events - -import io.tolgee.notifications.dto.NotificationCreateDto - -data class NotificationCreateEvent( - val notification: NotificationCreateDto, - val responsibleUserId: Long?, - val source: Any? = null, -) 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 deleted file mode 100644 index 980aeec1b55..00000000000 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/events/UserNotificationPushEvent.kt +++ /dev/null @@ -1,27 +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.events - -import io.tolgee.model.notifications.UserNotification - -/** - * Event sent when a set of users received a new notification. - */ -data class UserNotificationPushEvent( - val createdNotifications: Set, - val updatedNotifications: 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 deleted file mode 100644 index 16257e645eb..00000000000 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/ActivityEventListener.kt +++ /dev/null @@ -1,414 +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.listeners - -import io.tolgee.activity.data.ActivityType -import io.tolgee.activity.data.RevisionType -import io.tolgee.events.OnProjectActivityStoredEvent -import io.tolgee.model.Screenshot -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.service.language.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 - -private typealias SortedTranslations = List>> - -@Component -class ActivityEventListener( - private val applicationEventPublisher: ApplicationEventPublisher, - private val languageService: LanguageService, -) : Logging { - @EventListener - @Transactional - fun onActivityRevision(e: OnProjectActivityStoredEvent) { - // Using the Stored variant so `modifiedEntities` is populated. - - logger.trace( - "Received project activity event - {} on proj#{} ({} entities modified)", - e.activityRevision.type, - e.activityRevision.projectId, - e.activityRevision.modifiedEntities.size, - ) - - val projectId = e.activityRevision.projectId ?: return - val responsibleUserId = e.activityRevision.authorId - - when (e.activityRevision.type) { - // ACTIVITY_LANGUAGES_CREATED - ActivityType.CREATE_LANGUAGE -> - processSimpleActivity(NotificationType.ACTIVITY_LANGUAGES_CREATED, projectId, responsibleUserId, e) - - // ACTIVITY_KEYS_CREATED - ActivityType.CREATE_KEY -> - processSimpleActivity(NotificationType.ACTIVITY_KEYS_CREATED, projectId, responsibleUserId, e) - - // ACTIVITY_KEYS_UPDATED - ActivityType.KEY_TAGS_EDIT, - ActivityType.KEY_NAME_EDIT, - ActivityType.BATCH_TAG_KEYS, - ActivityType.COMPLEX_TAG_OPERATION, - ActivityType.BATCH_UNTAG_KEYS, - 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(projectId, responsibleUserId, e) - - // ACTIVITY_KEYS_SCREENSHOTS_UPLOADED - ActivityType.SCREENSHOT_ADD -> - processScreenshotUpdate(projectId, responsibleUserId, e) - - // ACTIVITY_TRANSLATIONS_* - ActivityType.SET_TRANSLATIONS, - ActivityType.SET_TRANSLATION_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, - -> - processSetTranslations(projectId, responsibleUserId, e) - - ActivityType.SET_OUTDATED_FLAG -> - 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, projectId, responsibleUserId, e) - - // ACTIVITY_KEYS_CREATED, ACTIVITY_TRANSLATIONS_* - ActivityType.IMPORT -> - processImport(projectId, responsibleUserId, 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.KEY_CHARACTER_LIMIT_EDIT, - ActivityType.KEY_SOFT_DELETE, - ActivityType.KEY_RESTORE, - ActivityType.KEY_HARD_DELETE, - ActivityType.BATCH_KEY_RESTORE, - ActivityType.BATCH_KEY_HARD_DELETE, - ActivityType.BATCH_ASSIGN_TRANSLATION_LABEL, - ActivityType.BATCH_UNASSIGN_TRANSLATION_LABEL, - ActivityType.TASKS_CREATE, - ActivityType.TASK_CREATE, - ActivityType.TASK_UPDATE, - ActivityType.TASK_KEYS_UPDATE, - ActivityType.TASK_FINISH, - ActivityType.TASK_CLOSE, - ActivityType.TASK_REOPEN, - ActivityType.TASK_KEY_UPDATE, - ActivityType.ORDER_TRANSLATION, - ActivityType.GLOSSARY_CREATE, - ActivityType.GLOSSARY_UPDATE, - ActivityType.GLOSSARY_DELETE, - ActivityType.GLOSSARY_IMPORT, - ActivityType.GLOSSARY_TERM_CREATE, - ActivityType.GLOSSARY_TERM_UPDATE, - ActivityType.GLOSSARY_TERM_DELETE, - ActivityType.GLOSSARY_TERM_TRANSLATION_UPDATE, - ActivityType.TRANSLATION_MEMORY_CREATE, - ActivityType.TRANSLATION_MEMORY_UPDATE, - ActivityType.TRANSLATION_MEMORY_DELETE, - ActivityType.TRANSLATION_MEMORY_ASSIGN_PROJECT, - ActivityType.TRANSLATION_MEMORY_UNASSIGN_PROJECT, - ActivityType.TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG, - ActivityType.TRANSLATION_MEMORY_ENTRY_CREATE, - ActivityType.TRANSLATION_MEMORY_ENTRY_UPDATE, - ActivityType.TRANSLATION_MEMORY_ENTRY_DELETE, - ActivityType.TRANSLATION_MEMORY_IMPORT, - ActivityType.TRANSLATION_MEMORY_COPY_FROM_PROJECT, - ActivityType.TRANSLATION_LABELS_EDIT, - ActivityType.TRANSLATION_LABEL_ASSIGN, - ActivityType.TRANSLATION_LABEL_CREATE, - ActivityType.TRANSLATION_LABEL_UPDATE, - ActivityType.TRANSLATION_LABEL_DELETE, - ActivityType.CREATE_SUGGESTION, - ActivityType.DECLINE_SUGGESTION, - ActivityType.ACCEPT_SUGGESTION, - ActivityType.REVERSE_SUGGESTION, - ActivityType.DELETE_SUGGESTION, - ActivityType.SUGGESTION_SET_ACTIVE, - ActivityType.AI_PROMPT_CREATE, - ActivityType.AI_PROMPT_UPDATE, - ActivityType.AI_PROMPT_DELETE, - ActivityType.BRANCH_CREATE, - ActivityType.BRANCH_RENAME, - ActivityType.BRANCH_DELETE, - ActivityType.BRANCH_PROTECTION_CHANGE, - ActivityType.BRANCH_MERGE, - ActivityType.QA_ISSUE_IGNORE, - ActivityType.QA_ISSUE_UNIGNORE, - 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, - 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, - ActivityType.HARD_DELETE_LANGUAGE, - null, - -> {} - } - } - - /** - * Handles activities that can be simply mapped to a corresponding notification without extra processing. - */ - private fun processSimpleActivity( - type: NotificationType, - projectId: Long, - responsibleUserId: Long?, - e: OnProjectActivityStoredEvent, - ) { - applicationEventPublisher.publishEvent( - NotificationCreateEvent( - NotificationCreateDto(type, projectId, e.activityRevision.modifiedEntities), - responsibleUserId, - source = e, - ), - ) - } - - /** - * Emits multiple notification create events depending on the details of the complex edition. - */ - private fun processComplexEdit( - projectId: Long, - responsibleUserId: Long?, - e: OnProjectActivityStoredEvent, - ) { - processComplexEditKeyUpdate(projectId, responsibleUserId, e) - processScreenshotUpdate(projectId, responsibleUserId, e) - processSetTranslations(projectId, responsibleUserId, e) - } - - private fun processComplexEditKeyUpdate( - 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")) - ) || - ( - it.entityClass == KeyMeta::class.simpleName && - it.modifications.containsKey("tags") - ) - } - - if (relevantEntities.isNotEmpty()) { - applicationEventPublisher.publishEvent( - NotificationCreateEvent( - NotificationCreateDto(NotificationType.ACTIVITY_KEYS_UPDATED, projectId, relevantEntities.toMutableList()), - responsibleUserId, - 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( - projectId: Long, - responsibleUserId: Long?, - e: OnProjectActivityStoredEvent, - modifiedEntities: List = e.activityRevision.modifiedEntities, - ) { - 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, projectId, translations), - responsibleUserId, - source = e, - ), - ) - } - } - } - - private fun sortTranslations( - entities: List, - baseLanguage: Long, - ): SortedTranslations { - val updatedSourceTranslations = mutableListOf() - val updatedTranslations = 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"] - - if (text != null) { - val languageId = it.describingRelations?.get("language")?.entityId - if (languageId == baseLanguage) { - updatedSourceTranslations.add(it) - } else { - updatedTranslations.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_TRANSLATION_REVIEWED, reviewedTranslations), - Pair(NotificationType.ACTIVITY_TRANSLATION_UNREVIEWED, unreviewedTranslations), - ) - } - - private fun processOutdatedFlagUpdate( - projectId: Long, - responsibleUserId: Long?, - 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, - projectId = projectId, - modifiedEntities = outdatedTranslations.toMutableList(), - ), - responsibleUserId, - source = e, - ), - ) - } - } - - private fun processScreenshotUpdate( - projectId: Long, - responsibleUserId: Long?, - 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, - projectId = projectId, - modifiedEntities = addedScreenshots.toMutableList(), - ), - responsibleUserId, - source = e, - ), - ) - } - } - - private fun processImport( - projectId: Long, - responsibleUserId: Long?, - e: OnProjectActivityStoredEvent, - ) { - 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()) { - applicationEventPublisher.publishEvent( - NotificationCreateEvent( - NotificationCreateDto(NotificationType.ACTIVITY_KEYS_CREATED, projectId, createdKeys.toMutableList()), - responsibleUserId, - source = e, - ), - ) - } - - if (updatedTranslations.isNotEmpty()) { - 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 deleted file mode 100644 index 3f846fa99ae..00000000000 --- a/backend/data/src/main/kotlin/io/tolgee/notifications/listeners/BatchJobListener.kt +++ /dev/null @@ -1,58 +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.listeners - -import io.tolgee.batch.events.OnBatchJobFailed -import io.tolgee.model.batch.BatchJob -import io.tolgee.notifications.NotificationType -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 - -@Component -class BatchJobListener( - private val applicationEventPublisher: ApplicationEventPublisher, - private val entityManager: EntityManager, -) : Logging { - @EventListener - fun onBatchJobError(e: OnBatchJobFailed) { - logger.trace( - "Received batch job failure event - job#{} on proj#{}", - e.job.id, - e.job.projectId, - ) - - val projectId = e.job.projectId ?: return - val job = entityManager.getReference(BatchJob::class.java, e.job.id) - applicationEventPublisher.publishEvent( - NotificationCreateEvent( - NotificationCreateDto( - type = NotificationType.BATCH_JOB_ERRORED, - projectId = projectId, - batchJob = job, - ), - source = e, - responsibleUserId = null, - ), - ) - } -} 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 bb2e9a07b7e..95f311264ca 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/UserAccountRepository.kt @@ -6,7 +6,6 @@ import io.tolgee.model.UserAccount import io.tolgee.model.enums.ThirdPartyAuthType import io.tolgee.model.views.UserAccountInProjectView import io.tolgee.model.views.UserAccountWithOrganizationRoleView -import io.tolgee.model.views.UserProjectMetadataView import org.springframework.context.annotation.Lazy import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable @@ -368,45 +367,6 @@ interface UserAccountRepository : JpaRepository { ) fun findDemoByUsernames(usernames: List): List - @Query( - """ - SELECT DISTINCT new io.tolgee.model.views.UserProjectMetadataView( - ua.id, - p.id, - org_r.type, - perm_org, - listagg(str(vl_org.id), ','), - perm, - listagg(str(vl.id), ','), - np_global, - np_project - ) - 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 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 - ua.deletedAt IS NULL AND ( - (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 - @Query( nativeQuery = true, value = PROJECT_PERMISSIONS_CTE + "select ua.id" + PROJECT_PERMISSIONS_MAIN, 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 deleted file mode 100644 index a3b5b3883bd..00000000000 --- a/backend/data/src/main/kotlin/io/tolgee/repository/notifications/NotificationPreferencesRepository.kt +++ /dev/null @@ -1,46 +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.notifications - -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 -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) - - @Modifying - @Query("DELETE FROM NotificationPreferences WHERE project.id = :projectId") - fun deleteAllByProjectId(projectId: 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 deleted file mode 100644 index 2bab9a6f9df..00000000000 --- a/backend/data/src/main/kotlin/io/tolgee/repository/notifications/UserNotificationRepository.kt +++ /dev/null @@ -1,171 +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.notifications - -import io.tolgee.model.UserAccount -import io.tolgee.model.notifications.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 countNotificationsByRecipientIdAndUnreadTrue(recipient: Long): Int - - @Query( - """ - FROM UserNotification un WHERE - 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: List, - pageable: Pageable, - ): List - - @Query( - """ - FROM UserNotification un - WHERE - un.unread = true AND - un.type = :type AND - un.project.id = :projectId AND - un.recipient IN :recipients - """, - ) - fun findCandidatesForNotificationDebouncing( - type: NotificationType, - projectId: Long, - recipients: Collection, - ): List - - @Query( - """ - SELECT un - FROM UserNotification un - INNER JOIN un.modifiedEntities me - WHERE - un.unread = true 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 - me.entityClass = 'Key' AND - me.entityId = :keyId - ) - ) - ORDER BY un.type DESC - """, - ) - fun findCandidatesForTranslationUpdateNotificationDebouncing( - type: NotificationType, - projectId: Long, - recipients: Collection, - keyId: Long, - ): List - - @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 - me.entityClass = 'TranslationComment' AND - de.entityClass = 'Translation' AND - de.entityId = :translationId 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( - 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, - ) - - @Modifying - @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.id = ?1 AND un.id IN ?2") - fun markAsUnread( - recipient: Long, - notifications: Collection, - ) - - @Modifying - @Query( - """ - UPDATE UserNotification un - SET un.unread = false, un.markedDoneAt = CURRENT_TIMESTAMP() - WHERE un.recipient.id = ?1 AND un.id IN ?2 - """, - ) - fun markAsDone( - recipient: Long, - notifications: Collection, - ) - - @Modifying - @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, - ) - - @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/ProjectHardDeletingService.kt b/backend/data/src/main/kotlin/io/tolgee/service/project/ProjectHardDeletingService.kt index 52c64fb6856..cab3db6ea37 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/project/ProjectHardDeletingService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/project/ProjectHardDeletingService.kt @@ -5,8 +5,6 @@ import io.tolgee.constants.Caches import io.tolgee.dtos.cacheable.ProjectDto import io.tolgee.events.OnProjectSoftDeleted import io.tolgee.model.Project -import io.tolgee.notifications.NotificationPreferencesService -import io.tolgee.notifications.UserNotificationService import io.tolgee.repository.ProjectRepository import io.tolgee.repository.qa.ProjectQaConfigRepository import io.tolgee.security.ProjectHolder @@ -64,10 +62,6 @@ class ProjectHardDeletingService( private val branchService: BranchService, private val entityManager: EntityManager, private val projectQaConfigRepository: ProjectQaConfigRepository, - @Lazy - private val userNotificationService: UserNotificationService, - @Lazy - private val notificationPreferencesService: NotificationPreferencesService, ) : Logging { @Transactional @CacheEvict(cacheNames = [Caches.PROJECTS], key = "#project.id") @@ -146,8 +140,6 @@ class ProjectHardDeletingService( entityManager.clear() bigMetaService.deleteAllByProjectId(projectId) - userNotificationService.deleteAllByProjectId(projectId) - notificationPreferencesService.deleteAllByProjectId(projectId) branchService.deleteAllByProjectId(projectId) projectQaConfigRepository.deleteAllByProjectId(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 183afaab299..3ff14f9b687 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 @@ -23,8 +23,6 @@ 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.authentication.AuthenticationFacade 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 2a55f83727e..529bd288119 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,7 +23,6 @@ import io.tolgee.model.enums.OrganizationRoleType import io.tolgee.model.enums.ProjectPermissionType import io.tolgee.model.enums.Scope import io.tolgee.model.translationAgency.TranslationAgency -import io.tolgee.model.views.UserProjectMetadataView import io.tolgee.repository.PermissionRepository import io.tolgee.service.CachedPermissionService import io.tolgee.service.language.LanguageService @@ -252,14 +251,6 @@ class PermissionService( return computed.getAdminOrSupporterPermissions(userRole) } - fun computeProjectPermission(userProjectMetadataView: UserProjectMetadataView): ComputedPermissionDto { - return computeProjectPermission( - userProjectMetadataView.organizationRole, - userProjectMetadataView.basePermissions, - userProjectMetadataView.permissions, - ) - } - 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 5a1c6358c6a..84b6ea06b28 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 @@ -27,9 +27,6 @@ import io.tolgee.model.notifications.NotificationType import io.tolgee.model.views.ExtendedUserAccountInProject import io.tolgee.model.views.UserAccountInProjectView 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 import io.tolgee.service.AiPlaygroundResultService import io.tolgee.service.AvatarService @@ -72,8 +69,6 @@ class UserAccountService( private val organizationService: OrganizationService, private val entityManager: EntityManager, private val currentDateProvider: CurrentDateProvider, - @Lazy private val userNotificationService: UserNotificationService, - @Lazy private val notificationPreferencesService: NotificationPreferencesService, private val cacheManager: CacheManager, @Lazy private val self: UserAccountService, @@ -254,9 +249,6 @@ class UserAccountService( entityManager.remove(it) } - userNotificationService.deleteAllByUserId(toDelete.id) - notificationPreferencesService.deleteAllByUserId(toDelete.id) - aiPlaygroundResultService.deleteResultsByUser(toDelete.id) userAccountRepository.softDeleteUser(toDelete, currentDateProvider.date) applicationEventPublisher.publishEvent(OnUserCountChanged(decrease = true, this)) @@ -530,10 +522,6 @@ class UserAccountService( } } - fun getAllConnectedUserProjectMetadataViews(projectId: Long): List { - return userAccountRepository.findAllUserProjectMetadataViews(projectId) - } - @Transactional @CacheEvict(cacheNames = [Caches.USER_ACCOUNTS], key = "#result.id") fun update( diff --git a/backend/data/src/main/resources/db/changelog/schema.xml b/backend/data/src/main/resources/db/changelog/schema.xml index 4cb8199da7c..e7901710457 100644 --- a/backend/data/src/main/resources/db/changelog/schema.xml +++ b/backend/data/src/main/resources/db/changelog/schema.xml @@ -5775,93 +5775,6 @@ ]]>
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -5888,9 +5801,6 @@ - - - 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 deleted file mode 100644 index 0a5bcdb11fa..00000000000 --- a/backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/NotificationsE2eDataController.kt +++ /dev/null @@ -1,55 +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.controllers.internal.e2eData - -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 -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() { - @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) - } - - override val testData: TestDataBuilder - get() = NotificationsTestData().root -} diff --git a/webapp/src/component/layout/TopBar/NotificationBell.tsx b/webapp/src/component/layout/TopBar/NotificationBell.tsx deleted file mode 100644 index 268a444d39c..00000000000 --- a/webapp/src/component/layout/TopBar/NotificationBell.tsx +++ /dev/null @@ -1,62 +0,0 @@ -/** - * 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/constants/links.tsx b/webapp/src/constants/links.tsx index 5c0ebfc440c..ff143236b69 100644 --- a/webapp/src/constants/links.tsx +++ b/webapp/src/constants/links.tsx @@ -185,13 +185,6 @@ export class LINKS { * Notifications */ - static NOTIFICATIONS = Link.ofRoot('notifications'); - - static NOTIFICATIONS_INBOX = Link.ofParent(LINKS.NOTIFICATIONS, 'inbox'); - - static NOTIFICATIONS_UNREAD = Link.ofParent(LINKS.NOTIFICATIONS, 'unread'); - - static NOTIFICATIONS_DONE = Link.ofParent(LINKS.NOTIFICATIONS, 'done'); /** * Administration diff --git a/webapp/src/views/notifications/NotificationsRouter.tsx b/webapp/src/views/notifications/NotificationsRouter.tsx deleted file mode 100644 index 8ebc63e0821..00000000000 --- a/webapp/src/views/notifications/NotificationsRouter.tsx +++ /dev/null @@ -1,64 +0,0 @@ -/** - * 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'; -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 = () => { - const { t } = useTranslate(); - - return ( - - - - - - - - - - - - - - - - ); -}; diff --git a/webapp/src/views/notifications/NotificationsView.tsx b/webapp/src/views/notifications/NotificationsView.tsx deleted file mode 100644 index 061f146f47b..00000000000 --- a/webapp/src/views/notifications/NotificationsView.tsx +++ /dev/null @@ -1,63 +0,0 @@ -/** - * 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 16ebcfa047be6b38257b84c4bda87510d01e8d33 Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Sat, 11 Jul 2026 15:39:32 +0200 Subject: [PATCH 47/57] feat: cover all groupable activity types with activity group definitions - add group types for key soft-delete/restore/hard-delete, character limit, labels, tasks, glossaries, translation memories, suggestions, AI prompts, branches and QA issues - fix copy-pasted source activity types on webhook/content-delivery groups - merge activity-group links into the surviving revision when batch chunk revisions are merged (FK violation broke batch job finalization) - OpenAPI: keep base ProjectActivityModel generic; register per-activity-type schemas as standalone models and type modified entities as arrays - regenerate frontend API schema; fix React 18 children typings in group components Not grouped (intentionally): hidden types (AUTOMATION, TASK_KEY_UPDATE, HARD_DELETE_LANGUAGE), enum values never set in code (ORDER_TRANSLATION, TRANSLATION_MEMORY_COPY_FROM_PROJECT), activities recording no logged entities (TRANSLATION_MEMORY_ENTRY_*/\*_PROJECT*, BRANCH_DELETE) --- .../activity/ProjectActivityModelEnhancer.kt | 27 +- .../groups/ProjectCreationGroupViewTest.kt | 2 - .../activity/groups/ActivityGroupType.kt | 409 +++- .../tolgee/batch/BatchJobActivityFinalizer.kt | 33 + .../groups/SimpleTableExpandedContent.tsx | 6 +- .../CollapsibleActivityGroup.tsx | 10 +- webapp/src/constants/links.tsx | 1 - webapp/src/service/apiSchema.generated.ts | 1822 +++++++++++++++++ .../src/service/apiSchemaTypes.generated.ts | 85 + 9 files changed, 2374 insertions(+), 21 deletions(-) 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 db530047c85..3a3f0e4e1fa 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 @@ -25,10 +25,10 @@ class ProjectActivityModelEnhancer( private val baseType = baseSchema.type fun enhance() { - baseSchema.required = null - baseSchema.properties = null - baseSchema.type = null - baseSchema.oneOf = generateSchemas() + // Registers per-activity-type schemas (ProjectActivityModel) as standalone + // named schemas. The base ProjectActivityModel stays generic — replacing it with a + // oneOf union breaks every consumer typing modifiedEntities as a plain map. + generateSchemas() } private fun generateSchemas(): MutableList> { @@ -54,15 +54,26 @@ class ProjectActivityModelEnhancer( return newProperties } + @Suppress("UNCHECKED_CAST") private fun getNewModifiedEntitiesProperty(activityType: ActivityType): Schema { - val properties = + val typeDefinitions = activityType.typeDefinitions - ?.map { (entityClass, definition) -> + ?: return baseProperties["modifiedEntities"] as Schema + + val properties = + typeDefinitions + .map { (entityClass, definition) -> val schema = activityType.createModifiedEntityModel(entityClass) schema.properties["modifications"] = ModificationsSchemaGenerator(openApi).getModificationSchema(entityClass, definition) - entityClass.simpleName to schema - }?.toMap() + // one activity can modify many entities of the same class + val arraySchema = + Schema().apply { + type = "array" + items = schema + } + entityClass.simpleName to arraySchema + }.toMap() return Schema().apply { name = activityType.getModifiedEntitiesSchemaName() 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 index a3c885d10c0..01f6f0097b5 100644 --- a/backend/app/src/test/kotlin/io/tolgee/activity/groups/ProjectCreationGroupViewTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/activity/groups/ProjectCreationGroupViewTest.kt @@ -51,8 +51,6 @@ class ProjectCreationGroupViewTest : AuthorizedControllerTest() { node("deleted").isEqualTo(false) } - node("counts.Project").isEqualTo(1) - node("data") { node("id").isNumber node("name").isEqualTo("What a project") 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 8e8f76d7b6b..df6e84a197c 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 @@ -15,17 +15,30 @@ import io.tolgee.activity.groups.viewProviders.createProject.CreateProjectGroupM import io.tolgee.activity.groups.viewProviders.setTranslations.SetTranslationsGroupModelProvider import io.tolgee.model.Language import io.tolgee.model.Project +import io.tolgee.model.Prompt import io.tolgee.model.Screenshot +import io.tolgee.model.TranslationSuggestion +import io.tolgee.model.branching.Branch import io.tolgee.model.contentDelivery.ContentDeliveryConfig import io.tolgee.model.contentDelivery.ContentStorage import io.tolgee.model.enums.TranslationState +import io.tolgee.model.enums.TranslationSuggestionState +import io.tolgee.model.enums.qa.QaIssueState +import io.tolgee.model.glossary.Glossary +import io.tolgee.model.glossary.GlossaryTerm +import io.tolgee.model.glossary.GlossaryTermTranslation 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.qa.TranslationQaIssue +import io.tolgee.model.task.Task +import io.tolgee.model.task.TaskKey +import io.tolgee.model.translation.Label import io.tolgee.model.translation.Translation import io.tolgee.model.translation.TranslationComment +import io.tolgee.model.translationMemory.TranslationMemory import io.tolgee.model.webhook.WebhookConfig import kotlin.reflect.KClass @@ -220,6 +233,7 @@ enum class ActivityGroupType( ActivityType.COMPLEX_EDIT, ActivityType.BATCH_TAG_KEYS, ActivityType.BATCH_UNTAG_KEYS, + ActivityType.COMPLEX_TAG_OPERATION, ), matcher = DefaultMatcher( @@ -389,7 +403,7 @@ enum class ActivityGroupType( ), CONTENT_DELIVERY_CONFIG_DELETE( - listOf(ActivityType.CONTENT_DELIVERY_CONFIG_UPDATE), + listOf(ActivityType.CONTENT_DELIVERY_CONFIG_DELETE), matcher = DefaultMatcher( entityClass = ContentDeliveryConfig::class, @@ -434,7 +448,7 @@ enum class ActivityGroupType( ), WEBHOOK_CONFIG_UPDATE( - listOf(ActivityType.WEBHOOK_CONFIG_CREATE), + listOf(ActivityType.WEBHOOK_CONFIG_UPDATE), matcher = DefaultMatcher( entityClass = WebhookConfig::class, @@ -443,7 +457,7 @@ enum class ActivityGroupType( ), WEBHOOK_CONFIG_DELETE( - listOf(ActivityType.WEBHOOK_CONFIG_CREATE), + listOf(ActivityType.WEBHOOK_CONFIG_DELETE), matcher = DefaultMatcher( entityClass = WebhookConfig::class, @@ -451,6 +465,395 @@ enum class ActivityGroupType( ), ), + EDIT_KEY_CHARACTER_LIMIT( + listOf(ActivityType.KEY_CHARACTER_LIMIT_EDIT), + matcher = + DefaultMatcher( + entityClass = Key::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(Key::maxCharLimit), + ), + ), + + SOFT_DELETE_KEY( + listOf(ActivityType.KEY_SOFT_DELETE), + matcher = + DefaultMatcher( + entityClass = Key::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(Key::deletedAt), + allowedValues = mapOf(Key::deletedAt to notNull()), + ), + ), + + RESTORE_KEY( + listOf(ActivityType.KEY_RESTORE, ActivityType.BATCH_KEY_RESTORE), + matcher = + DefaultMatcher( + entityClass = Key::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(Key::deletedAt), + allowedValues = mapOf(Key::deletedAt to null), + ), + ), + + HARD_DELETE_KEY( + listOf(ActivityType.KEY_HARD_DELETE, ActivityType.BATCH_KEY_HARD_DELETE), + matcher = + DefaultMatcher( + entityClass = Key::class, + revisionTypes = listOf(RevisionType.DEL), + ), + ), + + SET_TRANSLATION_LABELS( + listOf( + ActivityType.TRANSLATION_LABEL_ASSIGN, + ActivityType.BATCH_ASSIGN_TRANSLATION_LABEL, + ActivityType.BATCH_UNASSIGN_TRANSLATION_LABEL, + ActivityType.TRANSLATION_LABELS_EDIT, + ), + matcher = + DefaultMatcher( + entityClass = Translation::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(Translation::labels), + ), + ), + + CREATE_TRANSLATION_LABEL( + listOf(ActivityType.TRANSLATION_LABEL_CREATE), + matcher = + DefaultMatcher( + entityClass = Label::class, + revisionTypes = listOf(RevisionType.ADD), + ), + ), + + EDIT_TRANSLATION_LABEL( + listOf(ActivityType.TRANSLATION_LABEL_UPDATE), + matcher = + DefaultMatcher( + entityClass = Label::class, + revisionTypes = listOf(RevisionType.MOD), + ), + ), + + DELETE_TRANSLATION_LABEL( + listOf(ActivityType.TRANSLATION_LABEL_DELETE), + matcher = + DefaultMatcher( + entityClass = Label::class, + revisionTypes = listOf(RevisionType.DEL), + ), + ), + + CREATE_TASK( + listOf(ActivityType.TASK_CREATE, ActivityType.TASKS_CREATE), + matcher = + DefaultMatcher( + entityClass = Task::class, + revisionTypes = listOf(RevisionType.ADD), + ), + ), + + EDIT_TASK( + listOf(ActivityType.TASK_UPDATE), + matcher = + DefaultMatcher( + entityClass = Task::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(Task::name, Task::description, Task::type, Task::dueDate, Task::assignees), + ), + ), + + FINISH_TASK( + listOf(ActivityType.TASK_FINISH), + matcher = + DefaultMatcher( + entityClass = Task::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(Task::state, Task::closedAt), + ), + ), + + CLOSE_TASK( + listOf(ActivityType.TASK_CLOSE), + matcher = + DefaultMatcher( + entityClass = Task::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(Task::state, Task::closedAt), + ), + ), + + REOPEN_TASK( + listOf(ActivityType.TASK_REOPEN), + matcher = + DefaultMatcher( + entityClass = Task::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(Task::state, Task::closedAt), + ), + ), + + UPDATE_TASK_KEYS( + listOf(ActivityType.TASK_KEYS_UPDATE), + matcher = + DefaultMatcher( + entityClass = TaskKey::class, + revisionTypes = listOf(RevisionType.ADD, RevisionType.DEL), + ), + ), + + CREATE_GLOSSARY( + listOf(ActivityType.GLOSSARY_CREATE), + matcher = + DefaultMatcher( + entityClass = Glossary::class, + revisionTypes = listOf(RevisionType.ADD), + ), + ), + + EDIT_GLOSSARY( + listOf(ActivityType.GLOSSARY_UPDATE), + matcher = + DefaultMatcher( + entityClass = Glossary::class, + revisionTypes = listOf(RevisionType.MOD), + ), + ), + + DELETE_GLOSSARY( + listOf(ActivityType.GLOSSARY_DELETE), + matcher = + DefaultMatcher( + entityClass = Glossary::class, + revisionTypes = listOf(RevisionType.DEL), + ), + ), + + IMPORT_GLOSSARY( + listOf(ActivityType.GLOSSARY_IMPORT), + matcher = + DefaultMatcher( + entityClass = GlossaryTerm::class, + revisionTypes = listOf(RevisionType.ADD, RevisionType.MOD), + ).or( + DefaultMatcher( + entityClass = GlossaryTermTranslation::class, + revisionTypes = listOf(RevisionType.ADD, RevisionType.MOD), + ), + ), + ), + + CREATE_GLOSSARY_TERM( + listOf(ActivityType.GLOSSARY_TERM_CREATE), + matcher = + DefaultMatcher( + entityClass = GlossaryTerm::class, + revisionTypes = listOf(RevisionType.ADD), + ), + ), + + EDIT_GLOSSARY_TERM( + listOf(ActivityType.GLOSSARY_TERM_UPDATE), + matcher = + DefaultMatcher( + entityClass = GlossaryTerm::class, + revisionTypes = listOf(RevisionType.MOD), + ), + ), + + DELETE_GLOSSARY_TERM( + listOf(ActivityType.GLOSSARY_TERM_DELETE), + matcher = + DefaultMatcher( + entityClass = GlossaryTerm::class, + revisionTypes = listOf(RevisionType.DEL), + ), + ), + + SET_GLOSSARY_TERM_TRANSLATION( + listOf(ActivityType.GLOSSARY_TERM_TRANSLATION_UPDATE), + matcher = + DefaultMatcher( + entityClass = GlossaryTermTranslation::class, + revisionTypes = listOf(RevisionType.ADD, RevisionType.MOD), + modificationProps = listOf(GlossaryTermTranslation::text), + ), + ), + + CREATE_TRANSLATION_MEMORY( + listOf(ActivityType.TRANSLATION_MEMORY_CREATE), + matcher = + DefaultMatcher( + entityClass = TranslationMemory::class, + revisionTypes = listOf(RevisionType.ADD), + ), + ), + + EDIT_TRANSLATION_MEMORY( + listOf(ActivityType.TRANSLATION_MEMORY_UPDATE), + matcher = + DefaultMatcher( + entityClass = TranslationMemory::class, + revisionTypes = listOf(RevisionType.MOD), + ), + ), + + DELETE_TRANSLATION_MEMORY( + listOf(ActivityType.TRANSLATION_MEMORY_DELETE), + matcher = + DefaultMatcher( + entityClass = TranslationMemory::class, + revisionTypes = listOf(RevisionType.DEL), + ), + ), + + CREATE_SUGGESTION( + listOf(ActivityType.CREATE_SUGGESTION), + matcher = + DefaultMatcher( + entityClass = TranslationSuggestion::class, + revisionTypes = listOf(RevisionType.ADD), + ), + ), + + DELETE_SUGGESTION( + listOf(ActivityType.DELETE_SUGGESTION), + matcher = + DefaultMatcher( + entityClass = TranslationSuggestion::class, + revisionTypes = listOf(RevisionType.DEL), + ), + ), + + DECLINE_SUGGESTION( + listOf(ActivityType.DECLINE_SUGGESTION), + matcher = + DefaultMatcher( + entityClass = TranslationSuggestion::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(TranslationSuggestion::state), + allowedValues = mapOf(TranslationSuggestion::state to TranslationSuggestionState.DECLINED), + ), + ), + + ACCEPT_SUGGESTION( + listOf(ActivityType.ACCEPT_SUGGESTION), + matcher = + DefaultMatcher( + entityClass = TranslationSuggestion::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(TranslationSuggestion::state), + allowedValues = mapOf(TranslationSuggestion::state to TranslationSuggestionState.ACCEPTED), + ), + ), + + SET_SUGGESTION_ACTIVE( + listOf(ActivityType.SUGGESTION_SET_ACTIVE, ActivityType.REVERSE_SUGGESTION), + matcher = + DefaultMatcher( + entityClass = TranslationSuggestion::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(TranslationSuggestion::state), + allowedValues = mapOf(TranslationSuggestion::state to TranslationSuggestionState.ACTIVE), + ), + ), + + CREATE_AI_PROMPT( + listOf(ActivityType.AI_PROMPT_CREATE), + matcher = + DefaultMatcher( + entityClass = Prompt::class, + revisionTypes = listOf(RevisionType.ADD), + ), + ), + + EDIT_AI_PROMPT( + listOf(ActivityType.AI_PROMPT_UPDATE), + matcher = + DefaultMatcher( + entityClass = Prompt::class, + revisionTypes = listOf(RevisionType.MOD), + ), + ), + + DELETE_AI_PROMPT( + listOf(ActivityType.AI_PROMPT_DELETE), + matcher = + DefaultMatcher( + entityClass = Prompt::class, + revisionTypes = listOf(RevisionType.DEL), + ), + ), + + CREATE_BRANCH( + listOf(ActivityType.BRANCH_CREATE), + matcher = + DefaultMatcher( + entityClass = Branch::class, + revisionTypes = listOf(RevisionType.ADD), + ), + ), + + RENAME_BRANCH( + listOf(ActivityType.BRANCH_RENAME), + matcher = + DefaultMatcher( + entityClass = Branch::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(Branch::name), + ), + ), + + CHANGE_BRANCH_PROTECTION( + listOf(ActivityType.BRANCH_PROTECTION_CHANGE), + matcher = + DefaultMatcher( + entityClass = Branch::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(Branch::isProtected), + ), + ), + + MERGE_BRANCH( + listOf(ActivityType.BRANCH_MERGE), + matcher = + DefaultMatcher( + entityClass = Key::class, + revisionTypes = listOf(RevisionType.ADD, RevisionType.MOD, RevisionType.DEL), + ).or( + DefaultMatcher( + entityClass = Translation::class, + revisionTypes = listOf(RevisionType.ADD, RevisionType.MOD, RevisionType.DEL), + ), + ), + ), + + IGNORE_QA_ISSUE( + listOf(ActivityType.QA_ISSUE_IGNORE), + matcher = + DefaultMatcher( + entityClass = TranslationQaIssue::class, + revisionTypes = listOf(RevisionType.MOD, RevisionType.ADD), + modificationProps = listOf(TranslationQaIssue::state), + allowedValues = mapOf(TranslationQaIssue::state to QaIssueState.IGNORED), + ), + ), + + UNIGNORE_QA_ISSUE( + listOf(ActivityType.QA_ISSUE_UNIGNORE), + matcher = + DefaultMatcher( + entityClass = TranslationQaIssue::class, + revisionTypes = listOf(RevisionType.MOD), + modificationProps = listOf(TranslationQaIssue::state), + allowedValues = mapOf(TranslationQaIssue::state to QaIssueState.OPEN), + ), + ), + ; fun getProvidingModelTypes(): Pair?, KClass<*>?>? { diff --git a/backend/data/src/main/kotlin/io/tolgee/batch/BatchJobActivityFinalizer.kt b/backend/data/src/main/kotlin/io/tolgee/batch/BatchJobActivityFinalizer.kt index 735eab1746e..5b0a6e1a877 100644 --- a/backend/data/src/main/kotlin/io/tolgee/batch/BatchJobActivityFinalizer.kt +++ b/backend/data/src/main/kotlin/io/tolgee/batch/BatchJobActivityFinalizer.kt @@ -56,6 +56,7 @@ class BatchJobActivityFinalizer( mergeDescribingEntities(activityRevisionIdToMergeInto, revisionIds) mergeModifiedEntities(activityRevisionIdToMergeInto, revisionIds) + mergeActivityGroups(activityRevisionIdToMergeInto, revisionIds) deleteUnusedRevisions(revisionIds) setJobIdAndAuthorIdToRevision(activityRevisionIdToMergeInto, job) applicationEventPublisher.publishEvent(OnBatchJobFinalized(job, activityRevisionIdToMergeInto)) @@ -121,6 +122,38 @@ class BatchJobActivityFinalizer( .executeUpdate() } + private fun mergeActivityGroups( + activityRevisionIdToMergeInto: Long, + revisionIds: MutableList, + ) { + if (revisionIds.isEmpty()) { + return + } + entityManager + .createNativeQuery( + """ + insert into activity_revision_activity_groups (activity_revisions_id, activity_groups_id) + select distinct :activityRevisionIdToMergeInto, activity_groups_id + from activity_revision_activity_groups + where activity_revisions_id in (:revisionIds) + and activity_groups_id not in ( + select activity_groups_id from activity_revision_activity_groups + where activity_revisions_id = :activityRevisionIdToMergeInto + ) + """, + ).setParameter("activityRevisionIdToMergeInto", activityRevisionIdToMergeInto) + .setParameter("revisionIds", revisionIds) + .executeUpdate() + + entityManager + .createNativeQuery( + """ + delete from activity_revision_activity_groups where activity_revisions_id in (:revisionIds) + """, + ).setParameter("revisionIds", revisionIds) + .executeUpdate() + } + private fun deleteUnusedRevisions(revisionIds: MutableList) { entityManager .createNativeQuery( diff --git a/webapp/src/component/activity/groups/SimpleTableExpandedContent.tsx b/webapp/src/component/activity/groups/SimpleTableExpandedContent.tsx index 971bc50d020..fdd3152d971 100644 --- a/webapp/src/component/activity/groups/SimpleTableExpandedContent.tsx +++ b/webapp/src/component/activity/groups/SimpleTableExpandedContent.tsx @@ -1,4 +1,4 @@ -import React, { FC } from 'react'; +import React, { FC, PropsWithChildren } from 'react'; import { UseQueryResult } from 'react-query'; import { PaginatedHateoasList } from '../../common/list/PaginatedHateoasList'; import { @@ -25,7 +25,7 @@ export const SimpleTableExpandedContent: FC = ( const fields = getFields(loadable); - const Table: FC = (props) => { + const Table: FC = (props) => { return {props.children}; }; @@ -45,7 +45,7 @@ export const SimpleTableExpandedContent: FC = ( ); }; -const TheTable: FC<{ headItems: string[] }> = (props) => { +const TheTable: FC> = (props) => { return ( diff --git a/webapp/src/component/activity/groups/groupTypeComponents/CollapsibleActivityGroup.tsx b/webapp/src/component/activity/groups/groupTypeComponents/CollapsibleActivityGroup.tsx index e9e13467436..07b68117653 100644 --- a/webapp/src/component/activity/groups/groupTypeComponents/CollapsibleActivityGroup.tsx +++ b/webapp/src/component/activity/groups/groupTypeComponents/CollapsibleActivityGroup.tsx @@ -1,9 +1,11 @@ -import React, { FC } from 'react'; +import React, { FC, PropsWithChildren } from 'react'; import { Box, Button } from '@mui/material'; -export const CollapsibleActivityGroup: FC<{ - expandedChildren?: React.ReactNode; -}> = (props) => { +export const CollapsibleActivityGroup: FC< + PropsWithChildren<{ + expandedChildren?: React.ReactNode; + }> +> = (props) => { const [expanded, setExpanded] = React.useState(false); const expandedContent = expanded diff --git a/webapp/src/constants/links.tsx b/webapp/src/constants/links.tsx index ff143236b69..54ed663f5b6 100644 --- a/webapp/src/constants/links.tsx +++ b/webapp/src/constants/links.tsx @@ -185,7 +185,6 @@ export class LINKS { * Notifications */ - /** * Administration */ diff --git a/webapp/src/service/apiSchema.generated.ts b/webapp/src/service/apiSchema.generated.ts index 74c548fd153..8b62c7b8f8f 100644 --- a/webapp/src/service/apiSchema.generated.ts +++ b/webapp/src/service/apiSchema.generated.ts @@ -427,6 +427,13 @@ export interface paths { "/v2/projects/{projectId}/activity": { get: operations["getActivity"]; }; + "/v2/projects/{projectId}/activity/group-items/create-key/{groupId}": { + get: operations["getCreateKeyItems"]; + }; + "/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/revisions/{revisionId}": { get: operations["getSingleRevision"]; }; @@ -1306,6 +1313,1585 @@ export interface components { AcceptAuthProviderChangeRequest: { id: string; }; + ActivityGroupAcceptSuggestionModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "ACCEPT_SUGGESTION"; + }; + ActivityGroupAddScreenshotModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "ADD_SCREENSHOT"; + }; + ActivityGroupAddTranslationCommentModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "ADD_TRANSLATION_COMMENT"; + }; + ActivityGroupAutoTranslateModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "AUTO_TRANSLATE"; + }; + ActivityGroupBatchClearTranslationsModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "BATCH_CLEAR_TRANSLATIONS"; + }; + ActivityGroupBatchCopyTranslationsModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "BATCH_COPY_TRANSLATIONS"; + }; + ActivityGroupBatchMachineTranslateModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "BATCH_MACHINE_TRANSLATE"; + }; + ActivityGroupBatchPreTranslateByTmModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "BATCH_PRE_TRANSLATE_BY_TM"; + }; + ActivityGroupBatchSetTranslationStateModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "BATCH_SET_TRANSLATION_STATE"; + }; + ActivityGroupChangeBranchProtectionModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CHANGE_BRANCH_PROTECTION"; + }; + ActivityGroupCloseTaskModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CLOSE_TASK"; + }; + ActivityGroupContentDeliveryConfigCreateModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CONTENT_DELIVERY_CONFIG_CREATE"; + }; + ActivityGroupContentDeliveryConfigDeleteModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CONTENT_DELIVERY_CONFIG_DELETE"; + }; + ActivityGroupContentDeliveryConfigUpdateModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CONTENT_DELIVERY_CONFIG_UPDATE"; + }; + ActivityGroupContentStorageCreateModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CONTENT_STORAGE_CREATE"; + }; + ActivityGroupContentStorageDeleteModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CONTENT_STORAGE_DELETE"; + }; + ActivityGroupContentStorageUpdateModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CONTENT_STORAGE_UPDATE"; + }; + ActivityGroupCreateAiPromptModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CREATE_AI_PROMPT"; + }; + ActivityGroupCreateBranchModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CREATE_BRANCH"; + }; + ActivityGroupCreateGlossaryModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CREATE_GLOSSARY"; + }; + ActivityGroupCreateGlossaryTermModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CREATE_GLOSSARY_TERM"; + }; + ActivityGroupCreateKeyModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + data?: { + /** Format: int32 */ + keyCount?: number; + }; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CREATE_KEY"; + }; + ActivityGroupCreateLanguageModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CREATE_LANGUAGE"; + }; + ActivityGroupCreateProjectModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + data?: { + description?: string; + /** Format: int64 */ + id?: number; + languages?: components["schemas"]["ActivityGroupLanguageModel"][]; + name?: string; + }; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CREATE_PROJECT"; + }; + ActivityGroupCreateSuggestionModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CREATE_SUGGESTION"; + }; + ActivityGroupCreateTaskModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CREATE_TASK"; + }; + ActivityGroupCreateTranslationLabelModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CREATE_TRANSLATION_LABEL"; + }; + ActivityGroupCreateTranslationMemoryModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CREATE_TRANSLATION_MEMORY"; + }; + ActivityGroupDeclineSuggestionModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "DECLINE_SUGGESTION"; + }; + ActivityGroupDeleteAiPromptModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "DELETE_AI_PROMPT"; + }; + ActivityGroupDeleteGlossaryModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "DELETE_GLOSSARY"; + }; + ActivityGroupDeleteGlossaryTermModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "DELETE_GLOSSARY_TERM"; + }; + ActivityGroupDeleteKeyModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "DELETE_KEY"; + }; + ActivityGroupDeleteLanguageModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "DELETE_LANGUAGE"; + }; + ActivityGroupDeleteScreenshotModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "DELETE_SCREENSHOT"; + }; + ActivityGroupDeleteSuggestionModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "DELETE_SUGGESTION"; + }; + ActivityGroupDeleteTranslationCommentModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "DELETE_TRANSLATION_COMMENT"; + }; + ActivityGroupDeleteTranslationLabelModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "DELETE_TRANSLATION_LABEL"; + }; + ActivityGroupDeleteTranslationMemoryModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "DELETE_TRANSLATION_MEMORY"; + }; + ActivityGroupDismissAutoTranslatedStateModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "DISMISS_AUTO_TRANSLATED_STATE"; + }; + ActivityGroupEditAiPromptModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "EDIT_AI_PROMPT"; + }; + ActivityGroupEditGlossaryModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "EDIT_GLOSSARY"; + }; + ActivityGroupEditGlossaryTermModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "EDIT_GLOSSARY_TERM"; + }; + ActivityGroupEditKeyCharacterLimitModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "EDIT_KEY_CHARACTER_LIMIT"; + }; + ActivityGroupEditKeyNameModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "EDIT_KEY_NAME"; + }; + ActivityGroupEditKeyTagsModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "EDIT_KEY_TAGS"; + }; + ActivityGroupEditLanguageModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "EDIT_LANGUAGE"; + }; + ActivityGroupEditProjectModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "EDIT_PROJECT"; + }; + ActivityGroupEditTaskModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "EDIT_TASK"; + }; + ActivityGroupEditTranslationCommentModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "EDIT_TRANSLATION_COMMENT"; + }; + ActivityGroupEditTranslationLabelModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "EDIT_TRANSLATION_LABEL"; + }; + ActivityGroupEditTranslationMemoryModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "EDIT_TRANSLATION_MEMORY"; + }; + ActivityGroupFinishTaskModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "FINISH_TASK"; + }; + ActivityGroupHardDeleteKeyModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "HARD_DELETE_KEY"; + }; + ActivityGroupIgnoreQaIssueModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "IGNORE_QA_ISSUE"; + }; + ActivityGroupImportGlossaryModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "IMPORT_GLOSSARY"; + }; + ActivityGroupImportModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "IMPORT"; + }; + ActivityGroupLanguageModel: { + flagEmoji?: string; + /** Format: int64 */ + id?: number; + name?: string; + originalName?: string; + tag?: string; + }; + ActivityGroupMergeBranchModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "MERGE_BRANCH"; + }; + ActivityGroupModel: + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + data?: { + /** Format: int32 */ + keyCount?: number; + }; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CREATE_KEY"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "EDIT_KEY_NAME"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "DELETE_KEY"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "SET_TRANSLATION_STATE"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "REVIEW"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "SET_BASE_TRANSLATION"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + data?: { + /** Format: int32 */ + translationCount?: number; + }; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "SET_TRANSLATIONS"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "DISMISS_AUTO_TRANSLATED_STATE"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "SET_OUTDATED_FLAG"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "ADD_TRANSLATION_COMMENT"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "DELETE_TRANSLATION_COMMENT"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "EDIT_TRANSLATION_COMMENT"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "SET_TRANSLATION_COMMENT_STATE"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "DELETE_SCREENSHOT"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "ADD_SCREENSHOT"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "EDIT_KEY_TAGS"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "IMPORT"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CREATE_LANGUAGE"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "EDIT_LANGUAGE"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "DELETE_LANGUAGE"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + data?: { + description?: string; + /** Format: int64 */ + id?: number; + languages?: components["schemas"]["ActivityGroupLanguageModel"][]; + name?: string; + }; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CREATE_PROJECT"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "EDIT_PROJECT"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "NAMESPACE_EDIT"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "BATCH_PRE_TRANSLATE_BY_TM"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "BATCH_MACHINE_TRANSLATE"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "AUTO_TRANSLATE"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "BATCH_CLEAR_TRANSLATIONS"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "BATCH_COPY_TRANSLATIONS"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "BATCH_SET_TRANSLATION_STATE"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CONTENT_DELIVERY_CONFIG_CREATE"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CONTENT_DELIVERY_CONFIG_UPDATE"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CONTENT_DELIVERY_CONFIG_DELETE"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CONTENT_STORAGE_CREATE"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CONTENT_STORAGE_UPDATE"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CONTENT_STORAGE_DELETE"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "WEBHOOK_CONFIG_CREATE"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "WEBHOOK_CONFIG_UPDATE"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "WEBHOOK_CONFIG_DELETE"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "EDIT_KEY_CHARACTER_LIMIT"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "SOFT_DELETE_KEY"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "RESTORE_KEY"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "HARD_DELETE_KEY"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "SET_TRANSLATION_LABELS"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CREATE_TRANSLATION_LABEL"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "EDIT_TRANSLATION_LABEL"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "DELETE_TRANSLATION_LABEL"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CREATE_TASK"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "EDIT_TASK"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "FINISH_TASK"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CLOSE_TASK"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "REOPEN_TASK"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "UPDATE_TASK_KEYS"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CREATE_GLOSSARY"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "EDIT_GLOSSARY"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "DELETE_GLOSSARY"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "IMPORT_GLOSSARY"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CREATE_GLOSSARY_TERM"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "EDIT_GLOSSARY_TERM"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "DELETE_GLOSSARY_TERM"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "SET_GLOSSARY_TERM_TRANSLATION"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CREATE_TRANSLATION_MEMORY"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "EDIT_TRANSLATION_MEMORY"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "DELETE_TRANSLATION_MEMORY"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CREATE_SUGGESTION"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "DELETE_SUGGESTION"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "DECLINE_SUGGESTION"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "ACCEPT_SUGGESTION"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "SET_SUGGESTION_ACTIVE"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CREATE_AI_PROMPT"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "EDIT_AI_PROMPT"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "DELETE_AI_PROMPT"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CREATE_BRANCH"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "RENAME_BRANCH"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "CHANGE_BRANCH_PROTECTION"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "MERGE_BRANCH"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "IGNORE_QA_ISSUE"; + } + | { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "UNIGNORE_QA_ISSUE"; + }; + ActivityGroupNamespaceEditModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "NAMESPACE_EDIT"; + }; + ActivityGroupRenameBranchModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "RENAME_BRANCH"; + }; + ActivityGroupReopenTaskModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "REOPEN_TASK"; + }; + ActivityGroupRestoreKeyModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "RESTORE_KEY"; + }; + ActivityGroupReviewModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "REVIEW"; + }; + ActivityGroupSetBaseTranslationModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "SET_BASE_TRANSLATION"; + }; + ActivityGroupSetGlossaryTermTranslationModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "SET_GLOSSARY_TERM_TRANSLATION"; + }; + ActivityGroupSetOutdatedFlagModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "SET_OUTDATED_FLAG"; + }; + ActivityGroupSetSuggestionActiveModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "SET_SUGGESTION_ACTIVE"; + }; + ActivityGroupSetTranslationCommentStateModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "SET_TRANSLATION_COMMENT_STATE"; + }; + ActivityGroupSetTranslationLabelsModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "SET_TRANSLATION_LABELS"; + }; + ActivityGroupSetTranslationStateModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "SET_TRANSLATION_STATE"; + }; + ActivityGroupSetTranslationsModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + data?: { + /** Format: int32 */ + translationCount?: number; + }; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "SET_TRANSLATIONS"; + }; + ActivityGroupSoftDeleteKeyModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "SOFT_DELETE_KEY"; + }; + ActivityGroupUnignoreQaIssueModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "UNIGNORE_QA_ISSUE"; + }; + ActivityGroupUpdateTaskKeysModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "UPDATE_TASK_KEYS"; + }; + ActivityGroupWebhookConfigCreateModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "WEBHOOK_CONFIG_CREATE"; + }; + ActivityGroupWebhookConfigDeleteModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "WEBHOOK_CONFIG_DELETE"; + }; + ActivityGroupWebhookConfigUpdateModel: { + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + mentionedLanguageIds: number[]; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "WEBHOOK_CONFIG_UPDATE"; + }; AiPlaygroundResultModel: { contextDescription?: string; /** Format: int64 */ @@ -2559,6 +4145,43 @@ export interface components { tags?: string[]; translations?: { [key: string]: string }; }; + CreateKeyGroupItemModel: { + /** Format: int64 */ + baseLanguageId?: number; + /** @description The base translation value entered when key was created */ + baseTranslationText?: string; + /** @description Custom values of the key */ + custom?: { [key: string]: unknown }; + /** + * @description Description of key + * @example This key is used on homepage. It's a label of sign up button. + */ + description?: string; + /** + * Format: int64 + * @description Id of key record + */ + id: number; + /** @description If key is pluralized. If it will be reflected in the editor */ + isPlural: boolean; + /** + * @description Name of key + * @example this_is_super_key + */ + name: string; + /** + * @description Namespace of key + * @example homepage + */ + namespace?: string; + /** @description The argument name for the plural */ + pluralArgName?: string; + tags: string[]; + }; + CreateKeyGroupModel: { + /** Format: int32 */ + keyCount?: number; + }; CreateMultipleTasksRequest: { tasks: components["schemas"]["CreateTaskRequest"][]; }; @@ -2593,6 +4216,13 @@ export interface components { */ expiresAt?: number; }; + CreateProjectGroupModel: { + description?: string; + /** Format: int64 */ + id?: number; + languages?: components["schemas"]["ActivityGroupLanguageModel"][]; + name?: string; + }; CreateProjectRequest: { /** @description Tag of one of created languages, to select it as base language. If not provided, first language will be selected as base. */ baseLanguageTag?: string; @@ -4545,6 +6175,12 @@ export interface components { size?: number; sort?: string[]; }; + PagedModelActivityGroupModel: { + _embedded?: { + groups?: components["schemas"]["ActivityGroupModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; PagedModelApiKeyModel: { _embedded?: { apiKeys?: components["schemas"]["ApiKeyModel"][]; @@ -4593,6 +6229,12 @@ export interface components { }; page?: components["schemas"]["PageMetadata"]; }; + PagedModelCreateKeyGroupItemModel: { + _embedded?: { + items?: components["schemas"]["CreateKeyGroupItemModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; PagedModelImportFileIssueModel: { _embedded?: { importFileIssues?: components["schemas"]["ImportFileIssueModel"][]; @@ -6229,6 +7871,10 @@ export interface components { */ description?: string; }; + SetTranslationsGroupModel: { + /** Format: int32 */ + translationCount?: number; + }; SetTranslationsResponseModel: { /** * Format: int64 @@ -13597,6 +15243,182 @@ export interface operations { }; }; }; + 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 */ + 400: { + content: { + "application/json": string; + }; + }; + /** Unauthorized */ + 401: { + content: { + "application/json": string; + }; + }; + /** Forbidden */ + 403: { + content: { + "application/json": string; + }; + }; + /** Not Found */ + 404: { + content: { + "application/json": string; + }; + }; + }; + }; + /** 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[]; + filterType?: + | "CREATE_KEY" + | "EDIT_KEY_NAME" + | "DELETE_KEY" + | "SET_TRANSLATION_STATE" + | "REVIEW" + | "SET_BASE_TRANSLATION" + | "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" + | "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" + | "EDIT_KEY_CHARACTER_LIMIT" + | "SOFT_DELETE_KEY" + | "RESTORE_KEY" + | "HARD_DELETE_KEY" + | "SET_TRANSLATION_LABELS" + | "CREATE_TRANSLATION_LABEL" + | "EDIT_TRANSLATION_LABEL" + | "DELETE_TRANSLATION_LABEL" + | "CREATE_TASK" + | "EDIT_TASK" + | "FINISH_TASK" + | "CLOSE_TASK" + | "REOPEN_TASK" + | "UPDATE_TASK_KEYS" + | "CREATE_GLOSSARY" + | "EDIT_GLOSSARY" + | "DELETE_GLOSSARY" + | "IMPORT_GLOSSARY" + | "CREATE_GLOSSARY_TERM" + | "EDIT_GLOSSARY_TERM" + | "DELETE_GLOSSARY_TERM" + | "SET_GLOSSARY_TERM_TRANSLATION" + | "CREATE_TRANSLATION_MEMORY" + | "EDIT_TRANSLATION_MEMORY" + | "DELETE_TRANSLATION_MEMORY" + | "CREATE_SUGGESTION" + | "DELETE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "SET_SUGGESTION_ACTIVE" + | "CREATE_AI_PROMPT" + | "EDIT_AI_PROMPT" + | "DELETE_AI_PROMPT" + | "CREATE_BRANCH" + | "RENAME_BRANCH" + | "CHANGE_BRANCH_PROTECTION" + | "MERGE_BRANCH" + | "IGNORE_QA_ISSUE" + | "UNIGNORE_QA_ISSUE"; + filterLanguageIdIn?: number[]; + filterAuthorUserIdIn?: number[]; + }; + path: { + projectId: number; + }; + }; + responses: { + /** OK */ + 200: { + content: { + "application/hal+json": components["schemas"]["PagedModelActivityGroupModel"]; + }; + }; + /** Bad Request */ + 400: { + content: { + "application/json": string; + }; + }; + /** Unauthorized */ + 401: { + content: { + "application/json": string; + }; + }; + /** Forbidden */ + 403: { + content: { + "application/json": string; + }; + }; + /** Not Found */ + 404: { + content: { + "application/json": string; + }; + }; + }; + }; getSingleRevision: { parameters: { path: { diff --git a/webapp/src/service/apiSchemaTypes.generated.ts b/webapp/src/service/apiSchemaTypes.generated.ts index e659c400ee0..abc13fb2c50 100644 --- a/webapp/src/service/apiSchemaTypes.generated.ts +++ b/webapp/src/service/apiSchemaTypes.generated.ts @@ -5,6 +5,85 @@ import type { components } from './apiSchema.generated'; export type AcceptAuthProviderChangeRequest = components['schemas']['AcceptAuthProviderChangeRequest']; +export type ActivityGroupAcceptSuggestionModel = components['schemas']['ActivityGroupAcceptSuggestionModel']; +export type ActivityGroupAddScreenshotModel = components['schemas']['ActivityGroupAddScreenshotModel']; +export type ActivityGroupAddTranslationCommentModel = components['schemas']['ActivityGroupAddTranslationCommentModel']; +export type ActivityGroupAutoTranslateModel = components['schemas']['ActivityGroupAutoTranslateModel']; +export type ActivityGroupBatchClearTranslationsModel = components['schemas']['ActivityGroupBatchClearTranslationsModel']; +export type ActivityGroupBatchCopyTranslationsModel = components['schemas']['ActivityGroupBatchCopyTranslationsModel']; +export type ActivityGroupBatchMachineTranslateModel = components['schemas']['ActivityGroupBatchMachineTranslateModel']; +export type ActivityGroupBatchPreTranslateByTmModel = components['schemas']['ActivityGroupBatchPreTranslateByTmModel']; +export type ActivityGroupBatchSetTranslationStateModel = components['schemas']['ActivityGroupBatchSetTranslationStateModel']; +export type ActivityGroupChangeBranchProtectionModel = components['schemas']['ActivityGroupChangeBranchProtectionModel']; +export type ActivityGroupCloseTaskModel = components['schemas']['ActivityGroupCloseTaskModel']; +export type ActivityGroupContentDeliveryConfigCreateModel = components['schemas']['ActivityGroupContentDeliveryConfigCreateModel']; +export type ActivityGroupContentDeliveryConfigDeleteModel = components['schemas']['ActivityGroupContentDeliveryConfigDeleteModel']; +export type ActivityGroupContentDeliveryConfigUpdateModel = components['schemas']['ActivityGroupContentDeliveryConfigUpdateModel']; +export type ActivityGroupContentStorageCreateModel = components['schemas']['ActivityGroupContentStorageCreateModel']; +export type ActivityGroupContentStorageDeleteModel = components['schemas']['ActivityGroupContentStorageDeleteModel']; +export type ActivityGroupContentStorageUpdateModel = components['schemas']['ActivityGroupContentStorageUpdateModel']; +export type ActivityGroupCreateAiPromptModel = components['schemas']['ActivityGroupCreateAiPromptModel']; +export type ActivityGroupCreateBranchModel = components['schemas']['ActivityGroupCreateBranchModel']; +export type ActivityGroupCreateGlossaryModel = components['schemas']['ActivityGroupCreateGlossaryModel']; +export type ActivityGroupCreateGlossaryTermModel = components['schemas']['ActivityGroupCreateGlossaryTermModel']; +export type ActivityGroupCreateKeyModel = components['schemas']['ActivityGroupCreateKeyModel']; +export type ActivityGroupCreateLanguageModel = components['schemas']['ActivityGroupCreateLanguageModel']; +export type ActivityGroupCreateProjectModel = components['schemas']['ActivityGroupCreateProjectModel']; +export type ActivityGroupCreateSuggestionModel = components['schemas']['ActivityGroupCreateSuggestionModel']; +export type ActivityGroupCreateTaskModel = components['schemas']['ActivityGroupCreateTaskModel']; +export type ActivityGroupCreateTranslationLabelModel = components['schemas']['ActivityGroupCreateTranslationLabelModel']; +export type ActivityGroupCreateTranslationMemoryModel = components['schemas']['ActivityGroupCreateTranslationMemoryModel']; +export type ActivityGroupDeclineSuggestionModel = components['schemas']['ActivityGroupDeclineSuggestionModel']; +export type ActivityGroupDeleteAiPromptModel = components['schemas']['ActivityGroupDeleteAiPromptModel']; +export type ActivityGroupDeleteGlossaryModel = components['schemas']['ActivityGroupDeleteGlossaryModel']; +export type ActivityGroupDeleteGlossaryTermModel = components['schemas']['ActivityGroupDeleteGlossaryTermModel']; +export type ActivityGroupDeleteKeyModel = components['schemas']['ActivityGroupDeleteKeyModel']; +export type ActivityGroupDeleteLanguageModel = components['schemas']['ActivityGroupDeleteLanguageModel']; +export type ActivityGroupDeleteScreenshotModel = components['schemas']['ActivityGroupDeleteScreenshotModel']; +export type ActivityGroupDeleteSuggestionModel = components['schemas']['ActivityGroupDeleteSuggestionModel']; +export type ActivityGroupDeleteTranslationCommentModel = components['schemas']['ActivityGroupDeleteTranslationCommentModel']; +export type ActivityGroupDeleteTranslationLabelModel = components['schemas']['ActivityGroupDeleteTranslationLabelModel']; +export type ActivityGroupDeleteTranslationMemoryModel = components['schemas']['ActivityGroupDeleteTranslationMemoryModel']; +export type ActivityGroupDismissAutoTranslatedStateModel = components['schemas']['ActivityGroupDismissAutoTranslatedStateModel']; +export type ActivityGroupEditAiPromptModel = components['schemas']['ActivityGroupEditAiPromptModel']; +export type ActivityGroupEditGlossaryModel = components['schemas']['ActivityGroupEditGlossaryModel']; +export type ActivityGroupEditGlossaryTermModel = components['schemas']['ActivityGroupEditGlossaryTermModel']; +export type ActivityGroupEditKeyCharacterLimitModel = components['schemas']['ActivityGroupEditKeyCharacterLimitModel']; +export type ActivityGroupEditKeyNameModel = components['schemas']['ActivityGroupEditKeyNameModel']; +export type ActivityGroupEditKeyTagsModel = components['schemas']['ActivityGroupEditKeyTagsModel']; +export type ActivityGroupEditLanguageModel = components['schemas']['ActivityGroupEditLanguageModel']; +export type ActivityGroupEditProjectModel = components['schemas']['ActivityGroupEditProjectModel']; +export type ActivityGroupEditTaskModel = components['schemas']['ActivityGroupEditTaskModel']; +export type ActivityGroupEditTranslationCommentModel = components['schemas']['ActivityGroupEditTranslationCommentModel']; +export type ActivityGroupEditTranslationLabelModel = components['schemas']['ActivityGroupEditTranslationLabelModel']; +export type ActivityGroupEditTranslationMemoryModel = components['schemas']['ActivityGroupEditTranslationMemoryModel']; +export type ActivityGroupFinishTaskModel = components['schemas']['ActivityGroupFinishTaskModel']; +export type ActivityGroupHardDeleteKeyModel = components['schemas']['ActivityGroupHardDeleteKeyModel']; +export type ActivityGroupIgnoreQaIssueModel = components['schemas']['ActivityGroupIgnoreQaIssueModel']; +export type ActivityGroupImportGlossaryModel = components['schemas']['ActivityGroupImportGlossaryModel']; +export type ActivityGroupImportModel = components['schemas']['ActivityGroupImportModel']; +export type ActivityGroupLanguageModel = components['schemas']['ActivityGroupLanguageModel']; +export type ActivityGroupMergeBranchModel = components['schemas']['ActivityGroupMergeBranchModel']; +export type ActivityGroupModel = components['schemas']['ActivityGroupModel']; +export type ActivityGroupNamespaceEditModel = components['schemas']['ActivityGroupNamespaceEditModel']; +export type ActivityGroupRenameBranchModel = components['schemas']['ActivityGroupRenameBranchModel']; +export type ActivityGroupReopenTaskModel = components['schemas']['ActivityGroupReopenTaskModel']; +export type ActivityGroupRestoreKeyModel = components['schemas']['ActivityGroupRestoreKeyModel']; +export type ActivityGroupReviewModel = components['schemas']['ActivityGroupReviewModel']; +export type ActivityGroupSetBaseTranslationModel = components['schemas']['ActivityGroupSetBaseTranslationModel']; +export type ActivityGroupSetGlossaryTermTranslationModel = components['schemas']['ActivityGroupSetGlossaryTermTranslationModel']; +export type ActivityGroupSetOutdatedFlagModel = components['schemas']['ActivityGroupSetOutdatedFlagModel']; +export type ActivityGroupSetSuggestionActiveModel = components['schemas']['ActivityGroupSetSuggestionActiveModel']; +export type ActivityGroupSetTranslationCommentStateModel = components['schemas']['ActivityGroupSetTranslationCommentStateModel']; +export type ActivityGroupSetTranslationLabelsModel = components['schemas']['ActivityGroupSetTranslationLabelsModel']; +export type ActivityGroupSetTranslationStateModel = components['schemas']['ActivityGroupSetTranslationStateModel']; +export type ActivityGroupSetTranslationsModel = components['schemas']['ActivityGroupSetTranslationsModel']; +export type ActivityGroupSoftDeleteKeyModel = components['schemas']['ActivityGroupSoftDeleteKeyModel']; +export type ActivityGroupUnignoreQaIssueModel = components['schemas']['ActivityGroupUnignoreQaIssueModel']; +export type ActivityGroupUpdateTaskKeysModel = components['schemas']['ActivityGroupUpdateTaskKeysModel']; +export type ActivityGroupWebhookConfigCreateModel = components['schemas']['ActivityGroupWebhookConfigCreateModel']; +export type ActivityGroupWebhookConfigDeleteModel = components['schemas']['ActivityGroupWebhookConfigDeleteModel']; +export type ActivityGroupWebhookConfigUpdateModel = components['schemas']['ActivityGroupWebhookConfigUpdateModel']; export type AiPlaygroundResultModel = components['schemas']['AiPlaygroundResultModel']; export type AiPlaygroundResultRequest = components['schemas']['AiPlaygroundResultRequest']; export type AnnouncementDto = components['schemas']['AnnouncementDto']; @@ -83,10 +162,13 @@ export type CreateBranchModel = components['schemas']['CreateBranchModel']; export type CreateGlossaryRequest = components['schemas']['CreateGlossaryRequest']; export type CreateGlossaryTermWithTranslationRequest = components['schemas']['CreateGlossaryTermWithTranslationRequest']; export type CreateKeyDto = components['schemas']['CreateKeyDto']; +export type CreateKeyGroupItemModel = components['schemas']['CreateKeyGroupItemModel']; +export type CreateKeyGroupModel = components['schemas']['CreateKeyGroupModel']; export type CreateMultipleTasksRequest = components['schemas']['CreateMultipleTasksRequest']; export type CreateMultipleTranslationMemoryEntriesRequest = components['schemas']['CreateMultipleTranslationMemoryEntriesRequest']; export type CreateMultipleTranslationMemoryEntriesTranslationRequest = components['schemas']['CreateMultipleTranslationMemoryEntriesTranslationRequest']; export type CreatePatDto = components['schemas']['CreatePatDto']; +export type CreateProjectGroupModel = components['schemas']['CreateProjectGroupModel']; export type CreateProjectRequest = components['schemas']['CreateProjectRequest']; export type CreateProviderRequest = components['schemas']['CreateProviderRequest']; export type CreateTaskRequest = components['schemas']['CreateTaskRequest']; @@ -200,6 +282,7 @@ export type OrganizationLanguageModel = components['schemas']['OrganizationLangu export type OrganizationModel = components['schemas']['OrganizationModel']; export type PageMetadata = components['schemas']['PageMetadata']; export type Pageable = components['schemas']['Pageable']; +export type PagedModelActivityGroupModel = components['schemas']['PagedModelActivityGroupModel']; export type PagedModelApiKeyModel = components['schemas']['PagedModelApiKeyModel']; export type PagedModelBatchJobModel = components['schemas']['PagedModelBatchJobModel']; export type PagedModelBranchMergeChangeModel = components['schemas']['PagedModelBranchMergeChangeModel']; @@ -208,6 +291,7 @@ export type PagedModelBranchMergeModel = components['schemas']['PagedModelBranch export type PagedModelBranchModel = components['schemas']['PagedModelBranchModel']; export type PagedModelContentDeliveryConfigModel = components['schemas']['PagedModelContentDeliveryConfigModel']; export type PagedModelContentStorageModel = components['schemas']['PagedModelContentStorageModel']; +export type PagedModelCreateKeyGroupItemModel = components['schemas']['PagedModelCreateKeyGroupItemModel']; export type PagedModelImportFileIssueModel = components['schemas']['PagedModelImportFileIssueModel']; export type PagedModelImportLanguageModel = components['schemas']['PagedModelImportLanguageModel']; export type PagedModelImportTranslationModel = components['schemas']['PagedModelImportTranslationModel']; @@ -324,6 +408,7 @@ export type SetLicenseKeyDto = components['schemas']['SetLicenseKeyDto']; export type SetMachineTranslationSettingsDto = components['schemas']['SetMachineTranslationSettingsDto']; export type SetOrganizationRoleDto = components['schemas']['SetOrganizationRoleDto']; export type SetProjectPromptCustomizationRequest = components['schemas']['SetProjectPromptCustomizationRequest']; +export type SetTranslationsGroupModel = components['schemas']['SetTranslationsGroupModel']; export type SetTranslationsResponseModel = components['schemas']['SetTranslationsResponseModel']; export type SetTranslationsStateStateRequest = components['schemas']['SetTranslationsStateStateRequest']; export type SetTranslationsWithKeyDto = components['schemas']['SetTranslationsWithKeyDto']; From a021343041ae8be0f5374fe587e33b6ea6dc7eb9 Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Sat, 11 Jul 2026 17:06:15 +0200 Subject: [PATCH 48/57] fix: address CI failures after activity grouping merge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - key modified-entity map by entity id once allocated (instance only as a fallback) — pure instance keying recorded the same row twice when Hibernate yielded multiple instances in one transaction (e.g. branch merge after entityManager.clear()), breaking inserts with duplicate PKs; set entityId on records created before id allocation so listeners see the real id - revert json-unit to 2.28.0 (main's version) and drop the custom number comparator — 2.38 compares BigDecimal scale strictly, breaking stats tests - add JOOQ to the liquibase runtime classpath (migration check loads entity classes referencing ActivityGroupType matchers) - add project_activity_title translation key used by the ActivityView - ktlint: line lengths, wildcard imports, jakarta @Transient in Permission --- backend/data/build.gradle | 1 + .../io/tolgee/activity/ActivityHolder.kt | 20 +++++++++++-- .../io/tolgee/activity/ActivityService.kt | 9 +++--- .../KeyBaseTranslationDescriber.kt | 7 +++-- .../activity/groups/ActivityGroupDto.kt | 2 +- .../activity/groups/ActivityGroupService.kt | 2 +- .../iterceptor/InterceptedEventsManager.kt | 29 +++++++++++-------- .../eventListeners/LanguageStatsListener.kt | 9 +++--- .../main/kotlin/io/tolgee/model/Permission.kt | 1 + .../model/activity/ActivityModifiedEntity.kt | 5 ++-- .../io/tolgee/fixtures/statusExpectations.kt | 13 +-------- .../ee/component/qa/QaActivityListener.kt | 6 ++-- settings.gradle | 2 +- webapp/src/i18n/en.json | 1 + webapp/src/views/projects/ActivityView.tsx | 2 +- 15 files changed, 65 insertions(+), 44 deletions(-) diff --git a/backend/data/build.gradle b/backend/data/build.gradle index a1023ad3a67..7cd7a4a5576 100644 --- a/backend/data/build.gradle +++ b/backend/data/build.gradle @@ -138,6 +138,7 @@ dependencies { liquibaseRuntime libs.kotlinReflect liquibaseRuntime sourceSets.main.output liquibaseRuntime 'org.springframework.boot:spring-boot-starter-data-jpa' + liquibaseRuntime libs.springJooq /** * Testing 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 b363cb5ecea..6dad59d79f2 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/ActivityHolder.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/ActivityHolder.kt @@ -10,7 +10,6 @@ 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( @@ -98,4 +97,21 @@ open class ActivityHolder( } } -typealias ModifiedEntitiesType = MutableMap, IdentityHashMap> +/** + * Inner map key is the entity id when it's already allocated, otherwise the entity + * instance itself (some ids are only assigned later in the transaction). Keying purely + * by instance would record the same row twice when Hibernate yields multiple instances + * of it in one transaction (e.g. after an entityManager.clear()). + */ +typealias ModifiedEntitiesType = + MutableMap, MutableMap> + +val Map.Entry.resolvedEntityId: Long + get() { + val key = key + return when { + key is Long -> key + key is EntityWithId && key.id != 0L -> key.id + else -> value.entityId + } + } 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 12139cb35fc..ca0432a123b 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/ActivityService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/ActivityService.kt @@ -77,13 +77,14 @@ class ActivityService( jdbcTemplate.batchUpdate( "INSERT INTO activity_modified_entity " + "(entity_class, entity_id, describing_data, " + - "describing_relations, modifications, revision_type, activity_revision_id, branch_id, additional_description) " + + "describing_relations, modifications, revision_type, activity_revision_id, branch_id, " + + "additional_description) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", list, 1000, - ) { 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, entry -> + val modifiedEntity = entry.value + val entityId = entry.resolvedEntityId ps.setString(1, modifiedEntity.entityClass) ps.setLong(2, entityId) ps.setObject(3, getJsonbObject(modifiedEntity.describingData)) 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 index 74c7818a19c..93ed5ef68e3 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/additionalDescribers/KeyBaseTranslationDescriber.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/additionalDescribers/KeyBaseTranslationDescriber.kt @@ -3,6 +3,7 @@ package io.tolgee.activity.additionalDescribers import io.tolgee.activity.ActivityAdditionalDescriber import io.tolgee.activity.ModifiedEntitiesType import io.tolgee.activity.data.RevisionType +import io.tolgee.activity.resolvedEntityId import io.tolgee.model.activity.ActivityDescribingEntity import io.tolgee.model.activity.ActivityEntityWithDescription import io.tolgee.model.activity.ActivityModifiedEntity @@ -29,8 +30,9 @@ class KeyBaseTranslationDescriber( val toDescribe = getToDescribe(activityRevision, modifiedEntities) val newKeyIds = modifiedEntities[Key::class] + ?.entries ?.mapNotNull { - if (it.value.revisionType == RevisionType.ADD) it.key.id else null + if (it.value.revisionType == RevisionType.ADD) it.resolvedEntityId else null }?.toSet() ?: emptySet() toDescribe.removeIf { (id, entity) -> @@ -74,7 +76,8 @@ class KeyBaseTranslationDescriber( it.entityId to it } - val modifiedEntities = allModifiedEntities[Key::class]?.map { it.key.id to it.value } ?: emptyList() + val modifiedEntities = + allModifiedEntities[Key::class]?.entries?.map { it.resolvedEntityId to it.value } ?: emptyList() return (describingRelations + modifiedEntities).toMutableList() } 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 de19fcac4fa..ec88e0d0248 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 @@ -1,6 +1,6 @@ package io.tolgee.activity.groups -import java.util.* +import java.util.Date data class ActivityGroupDto( val id: Long, 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 0fc74abd516..0fa4f725a4c 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 @@ -12,7 +12,7 @@ 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.* +import java.util.Date @Service class ActivityGroupService( 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 be139a67b71..50c5b40da33 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 @@ -34,7 +34,6 @@ 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 java.util.concurrent.ConcurrentHashMap import kotlin.reflect.KCallable import kotlin.reflect.KProperty @@ -202,18 +201,24 @@ class InterceptedEventsManager( revisionType: RevisionType, state: Array? = null, ): ActivityModifiedEntity { + val classMap = activityHolder.modifiedEntities.computeIfAbsent(entity::class) { mutableMapOf() } + if (entity.id != 0L) { + // the entity may have been recorded before its id was allocated + classMap.remove(entity)?.let { + it.entityId = entity.id + classMap.putIfAbsent(entity.id, it) + } + } val activityModifiedEntity = - activityHolder.modifiedEntities - .computeIfAbsent(entity::class) { IdentityHashMap() } - .computeIfAbsent( - entity, - ) { - ActivityModifiedEntity( - activityRevision, - entity::class.simpleName!!, - entity.id, - ).also { it.revisionType = revisionType } - } + classMap.computeIfAbsent( + if (entity.id != 0L) entity.id else entity, + ) { + ActivityModifiedEntity( + activityRevision, + entity::class.simpleName!!, + entity.id, + ).also { it.revisionType = revisionType } + } activityModifiedEntity.branchId = resolveBranchId(entity, revisionType, state) diff --git a/backend/data/src/main/kotlin/io/tolgee/component/eventListeners/LanguageStatsListener.kt b/backend/data/src/main/kotlin/io/tolgee/component/eventListeners/LanguageStatsListener.kt index 9692f3ed7f4..6618cc3130a 100644 --- a/backend/data/src/main/kotlin/io/tolgee/component/eventListeners/LanguageStatsListener.kt +++ b/backend/data/src/main/kotlin/io/tolgee/component/eventListeners/LanguageStatsListener.kt @@ -1,6 +1,7 @@ package io.tolgee.component.eventListeners import com.fasterxml.jackson.databind.ObjectMapper +import io.tolgee.activity.resolvedEntityId import io.tolgee.batch.data.BatchJobType import io.tolgee.batch.data.BatchTranslationTargetItem import io.tolgee.batch.events.OnBatchJobFinalized @@ -136,9 +137,9 @@ class LanguageStatsListener( ) { val keyIds = event.modifiedEntities[Key::class] - ?.keys + ?.entries .orEmpty() - .map { it.id } + .map { it.resolvedEntityId } if (keyIds.isEmpty()) return keyIds.chunked(IN_CLAUSE_BATCH_SIZE).forEach { chunk -> @@ -152,9 +153,9 @@ class LanguageStatsListener( ) { val translationIds = event.modifiedEntities[Translation::class] - ?.keys + ?.entries .orEmpty() - .map { it.id } + .map { it.resolvedEntityId } if (translationIds.isEmpty()) return translationIds.chunked(IN_CLAUSE_BATCH_SIZE).forEach { chunk -> 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 e3c3d577793..abaef6fb175 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt @@ -24,6 +24,7 @@ import jakarta.persistence.OneToOne import jakarta.persistence.PrePersist import jakarta.persistence.PreUpdate import jakarta.persistence.Table +import jakarta.persistence.Transient import org.hibernate.Hibernate import org.hibernate.annotations.Parameter import org.hibernate.annotations.Type 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 3cd7a6325a4..af5fab50b71 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 @@ -37,10 +37,11 @@ class ActivityModifiedEntity( @Id val entityClass: String, /** - * ID of the modified entity + * ID of the modified entity. Can be recorded before the entity's id is allocated; + * the interceptor sets the real id as soon as it's known. */ @Id - val entityId: Long, + var entityId: Long, ) : Serializable, ActivityEntityWithDescription { @Column(name = "branch_id") 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 95f46b102a0..a106fd56131 100644 --- a/backend/testing/src/main/kotlin/io/tolgee/fixtures/statusExpectations.kt +++ b/backend/testing/src/main/kotlin/io/tolgee/fixtures/statusExpectations.kt @@ -64,18 +64,7 @@ val ResultActions.andAssertThatJson: JsonAssert.ConfigurableJsonAssert fun ResultActions.andAssertThatJson(jsonAssert: JsonAssert.ConfigurableJsonAssert.() -> Unit): ResultActions { 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) - } - }, - ) - + jsonAssert(assertThatJson(this.andGetContentAsString)) this } return this diff --git a/ee/backend/app/src/main/kotlin/io/tolgee/ee/component/qa/QaActivityListener.kt b/ee/backend/app/src/main/kotlin/io/tolgee/ee/component/qa/QaActivityListener.kt index 30dcb858dd1..2e9e3893cfd 100644 --- a/ee/backend/app/src/main/kotlin/io/tolgee/ee/component/qa/QaActivityListener.kt +++ b/ee/backend/app/src/main/kotlin/io/tolgee/ee/component/qa/QaActivityListener.kt @@ -2,6 +2,7 @@ package io.tolgee.ee.component.qa import io.tolgee.activity.ActivityService import io.tolgee.activity.data.RevisionType +import io.tolgee.activity.resolvedEntityId import io.tolgee.batch.BatchJobService import io.tolgee.batch.data.BatchJobType import io.tolgee.batch.data.BatchTranslationTargetItem @@ -305,8 +306,9 @@ class QaActivityListener( private fun getLanguageTagChangedIds(event: OnProjectActivityEvent): List { val languageEntities = event.modifiedEntities[Language::class] ?: return emptyList() return languageEntities - .filter { (_, entity) -> entity.modifications.containsKey("tag") } - .map { (language, _) -> language.id } + .entries + .filter { it.value.modifications.containsKey("tag") } + .map { it.resolvedEntityId } } // endregion diff --git a/settings.gradle b/settings.gradle index 61eef30ffdd..d58c23259f2 100644 --- a/settings.gradle +++ b/settings.gradle @@ -56,7 +56,7 @@ dependencyResolutionManagement { library('commonsCodec', 'commons-codec:commons-codec:1.15') library('commonsLang', "org.apache.commons:commons-lang3:$commonsLang3Version") library('icu4j', 'com.ibm.icu:icu4j:74.2') - library('jsonUnitAssert', 'net.javacrumbs.json-unit:json-unit-assertj:2.38.0') + library('jsonUnitAssert', 'net.javacrumbs.json-unit:json-unit-assertj:2.28.0') library('amazonS3', "software.amazon.awssdk:s3:$amazonAwsSdkVersion") library('cloudfront', "software.amazon.awssdk:cloudfront:$amazonAwsSdkVersion") library('amazonSTS', "software.amazon.awssdk:sts:$amazonAwsSdkVersion") diff --git a/webapp/src/i18n/en.json b/webapp/src/i18n/en.json index 1e71fbf9361..1230f4438f4 100644 --- a/webapp/src/i18n/en.json +++ b/webapp/src/i18n/en.json @@ -1925,6 +1925,7 @@ "project_dashboard_strings_count_plural": "{value, plural, one {String} other {Strings}}", "project_dashboard_tag_count_plural": "{value, plural, one {Tag} other {Tags}}", "project_dashboard_task_count_plural": "{value, plural, one {Task} other {Tasks}}", + "project_activity_title": "Project Activity", "project_dashboard_title": "Project Dashboard", "project_dashboard_translated_percent": "Translated", "project_dashboard_translations_less_then_1_percent": "< 1%", diff --git a/webapp/src/views/projects/ActivityView.tsx b/webapp/src/views/projects/ActivityView.tsx index a023c6dd0a4..04d4242c73c 100644 --- a/webapp/src/views/projects/ActivityView.tsx +++ b/webapp/src/views/projects/ActivityView.tsx @@ -19,7 +19,7 @@ export const ActivityView = () => { }); return ( - + Date: Sat, 11 Jul 2026 17:54:55 +0200 Subject: [PATCH 49/57] feat: branch-aware activity groups, expanded views for all group types, grouped activity UI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - record branch_id on activity groups (split per branch at grouping time) and filter the /groups endpoint by branch like the regular activity feed - record baseLanguageId on activity revisions again (lost when main's ActivityRevisionInitializer replaced setProject) — fixes base/non-base translation matching and base-translation describing - generic group model provider: per-entity-class counts for every group type without a bespoke provider, plus a generic paged group-items endpoint returning raw modified entities - rebuild the grouped activity view: group cards with author, translated group-type labels, count chips and expandable per-type or generic item tables; translated labels for all 77 group types --- .../controllers/ProjectActivityController.kt | 7 + .../ProjectActivityGroupItemsController.kt | 26 + .../groups/ActivityGroupsCreationTest.kt | 6 +- .../activity/groups/ActivityGroupService.kt | 38 +- .../tolgee/activity/groups/ActivityGrouper.kt | 36 +- .../activity/groups/ActivityGroupsProvider.kt | 24 +- .../matchers/modifiedEntity/DefaultMatcher.kt | 2 + .../modifiedEntity/ModifiedEntityMatcher.kt | 9 + .../modifiedEntity/TranslationMatcher.kt | 3 + .../generic/GenericGroupItemModel.kt | 12 + .../generic/GenericGroupModel.kt | 5 + .../generic/GenericGroupModelProvider.kt | 63 ++ .../iterceptor/ActivityRevisionInitializer.kt | 2 +- .../io/tolgee/model/activity/ActivityGroup.kt | 4 + .../activity/ActivityGroupRepository.kt | 2 + .../main/resources/db/changelog/schema.xml | 5 + e2e/cypress/support/dataCyType.d.ts | 7 + .../activity/groups/ActivityGroupCard.tsx | 115 ++++ .../activity/groups/ActivityGroupItem.tsx | 67 +- .../groups/GenericGroupExpandedContent.tsx | 72 ++ .../groups/SimpleTableExpandedContent.tsx | 68 -- .../CollapsibleActivityGroup.tsx | 26 - .../CreateKeysActivityGroup.tsx | 82 ++- .../CreateProjectActivityGroup.tsx | 46 +- .../SetTranslationsActivityGroup.tsx | 35 - .../activity/groups/groupsConfiguration.tsx | 626 ++++++++++++++++++ webapp/src/i18n/en.json | 79 +++ webapp/src/service/apiSchema.generated.ts | 77 +++ .../src/service/apiSchemaTypes.generated.ts | 3 + webapp/src/views/projects/ActivityView.tsx | 26 +- 30 files changed, 1351 insertions(+), 222 deletions(-) create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/generic/GenericGroupItemModel.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/generic/GenericGroupModel.kt create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/generic/GenericGroupModelProvider.kt create mode 100644 webapp/src/component/activity/groups/ActivityGroupCard.tsx create mode 100644 webapp/src/component/activity/groups/GenericGroupExpandedContent.tsx delete mode 100644 webapp/src/component/activity/groups/SimpleTableExpandedContent.tsx delete mode 100644 webapp/src/component/activity/groups/groupTypeComponents/CollapsibleActivityGroup.tsx delete mode 100644 webapp/src/component/activity/groups/groupTypeComponents/SetTranslationsActivityGroup.tsx create mode 100644 webapp/src/component/activity/groups/groupsConfiguration.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 644a7a2bfd4..ee9c0300f77 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 @@ -143,12 +143,19 @@ class ProjectActivityController( fun getActivityGroups( @ParameterObject pageable: Pageable, @ParameterObject activityGroupFilters: ActivityGroupFilters, + @RequestParam(required = false) branch: String? = null, ): PagedModel { + projectFeatureGuard.checkIfUsed(Feature.BRANCHING, branch) + val activeBranch = branchService.getActiveNonDefaultBranch(projectHolder.project.id, branch) + val defaultBranchId = + if (activeBranch == null) branchService.getDefaultBranch(projectHolder.project.id)?.id else null val views = activityGroupService.getProjectActivityGroups( projectId = projectHolder.project.id, pageable, activityGroupFilters, + branchId = activeBranch?.id, + defaultBranchId = defaultBranchId, ) 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 index cad75a1e84d..d90ecf12705 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,9 +6,13 @@ 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.ActivityGroupService import io.tolgee.activity.groups.viewProviders.createKey.CreateKeyGroupItemModel import io.tolgee.activity.groups.viewProviders.createKey.CreateKeyGroupModelProvider +import io.tolgee.activity.groups.viewProviders.generic.GenericGroupItemModel +import io.tolgee.activity.groups.viewProviders.generic.GenericGroupModelProvider import io.tolgee.model.enums.Scope +import io.tolgee.security.ProjectHolder import io.tolgee.security.authentication.AllowApiAccess import io.tolgee.security.authorization.RequiresProjectPermissions import org.springdoc.core.annotations.ParameterObject @@ -29,6 +33,9 @@ import org.springframework.web.bind.annotation.RestController @Tag(name = "Activity Groups") class ProjectActivityGroupItemsController( private val createKeyGroupModelProvider: CreateKeyGroupModelProvider, + private val genericGroupModelProvider: GenericGroupModelProvider, + private val activityGroupService: ActivityGroupService, + private val projectHolder: ProjectHolder, ) { @Operation( summary = "Get CREATE_KEY group items", @@ -46,4 +53,23 @@ class ProjectActivityGroupItemsController( PageMetadata(data.pageable.pageSize.toLong(), data.pageable.pageNumber.toLong(), data.totalElements), ) } + + @Operation( + summary = "Get group items", + description = "Returns the modified entities of the group as generic items (any group type).", + ) + @GetMapping("/generic/{groupId}", produces = [MediaTypes.HAL_JSON_VALUE]) + @RequiresProjectPermissions([Scope.ACTIVITY_VIEW]) + @AllowApiAccess + fun getGenericItems( + @ParameterObject pageable: Pageable, + @PathVariable groupId: Long, + ): PagedModel { + val group = activityGroupService.getGroupInProject(groupId, projectHolder.project.id) + val data = genericGroupModelProvider.provideItems(group.type, groupId, pageable) + return PagedModel.of( + data.content, + PageMetadata(data.pageable.pageSize.toLong(), data.pageable.pageNumber.toLong(), data.totalElements), + ) + } } 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 09d1a7beeb5..a43a50c7906 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 @@ -80,7 +80,7 @@ class ActivityGroupsCreationTest : ProjectAuthControllerTest("/v2/projects/") { assertGroupsForActivity( ActivityGroupType.EDIT_KEY_NAME, ActivityGroupType.EDIT_KEY_TAGS, - ActivityGroupType.SET_TRANSLATIONS, + ActivityGroupType.SET_BASE_TRANSLATION, ActivityGroupType.REVIEW, ) } @@ -112,7 +112,7 @@ class ActivityGroupsCreationTest : ProjectAuthControllerTest("/v2/projects/") { executeTranslationUpdate("Test 4") assertGroupRevisionsCount(1) - assertLastGroupType(ActivityGroupType.SET_TRANSLATIONS) + assertLastGroupType(ActivityGroupType.SET_BASE_TRANSLATION) assertLastValue("Test 4") } @@ -126,7 +126,7 @@ class ActivityGroupsCreationTest : ProjectAuthControllerTest("/v2/projects/") { asserGroupCount(1) assertGroupRevisionsCount(3) - assertLastGroupType(ActivityGroupType.SET_TRANSLATIONS) + assertLastGroupType(ActivityGroupType.SET_BASE_TRANSLATION) assertLastValue("Test 3") } 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 0fa4f725a4c..fece64236a0 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 @@ -4,6 +4,7 @@ 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.exceptions.NotFoundException import io.tolgee.model.activity.ActivityGroup import io.tolgee.model.activity.ActivityRevision import io.tolgee.repository.activity.ActivityGroupRepository @@ -32,10 +33,11 @@ class ActivityGroupService( matchingStrings: Set, projectId: Long?, authorId: Long?, + branchId: Long? = null, ): Map { return matchingStrings.associateWith { matchingString -> - val existing = findSuitableExistingSuitableGroupDto(type, matchingString, projectId, authorId) - val group = existing ?: createActivityGroupDto(type, matchingString, projectId, authorId) + val existing = findSuitableExistingSuitableGroupDto(type, matchingString, projectId, authorId, branchId) + val group = existing ?: createActivityGroupDto(type, matchingString, projectId, authorId, branchId) group } } @@ -45,8 +47,9 @@ class ActivityGroupService( matchingString: String?, projectId: Long?, authorId: Long?, + branchId: Long?, ): ActivityGroupDto { - val entity = createActivityGroup(type, matchingString, projectId, authorId) + val entity = createActivityGroup(type, matchingString, projectId, authorId, branchId) return ActivityGroupDto( entity.id, entity.type, @@ -61,12 +64,14 @@ class ActivityGroupService( matchingString: String?, projectId: Long?, authorId: Long?, + branchId: Long?, ): ActivityGroup { return ActivityGroup( type = type, ).also { it.authorId = authorId it.projectId = projectId + it.branchId = branchId activityGroupRepository.saveAndFlush(it) it.matchingString = matchingString } @@ -77,8 +82,9 @@ class ActivityGroupService( matchingString: String?, projectId: Long?, authorId: Long?, + branchId: Long?, ): ActivityGroupDto? { - val latest = findLatest(type, matchingString, authorId, projectId) ?: return null + val latest = findLatest(type, matchingString, authorId, projectId, branchId) ?: return null if (latest.isTooOld || latest.lastActivityTooEarly) { return null } @@ -90,6 +96,7 @@ class ActivityGroupService( matchingString: String?, authorId: Long?, projectId: Long?, + branchId: Long?, ): ActivityGroupDto? { val result = activityGroupRepository.findLatest( @@ -97,6 +104,7 @@ class ActivityGroupService( matchingString = matchingString, authorId = authorId, projectId = projectId, + branchId = branchId, ) if (result.isEmpty()) { @@ -119,13 +127,33 @@ class ActivityGroupService( ) } + fun getGroupInProject( + groupId: Long, + projectId: Long, + ): ActivityGroup { + val group = activityGroupRepository.findById(groupId).orElse(null) + if (group == null || group.projectId != projectId) { + throw NotFoundException() + } + return group + } + @Transactional fun getProjectActivityGroups( projectId: Long, pageable: Pageable, activityGroupFilters: ActivityGroupFilters, + branchId: Long? = null, + defaultBranchId: Long? = null, ): PageImpl { - return ActivityGroupsProvider(projectId, pageable, activityGroupFilters, applicationContext).get() + return ActivityGroupsProvider( + projectId, + pageable, + activityGroupFilters, + applicationContext, + branchId, + defaultBranchId, + ).get() } private val ActivityGroupDto.isTooOld: Boolean 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 9e514157ffc..41764ff3240 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 @@ -13,10 +13,19 @@ class ActivityGrouper( private val applicationContext: ApplicationContext, ) { fun addToGroup() { - val groupTypes = findGroupTypes() - groupTypes.forEach { (type, matchingStrings) -> - getActivityGroupIds(type, matchingStrings).forEach { group -> - addToGroup(group.value) + ActivityGroupType.entries.forEach { type -> + val matchingEntities = type.matchingEntities + if (matchingEntities.isEmpty()) { + return@forEach + } + matchingEntities.groupBy { it.branchId }.forEach { (branchId, entities) -> + val matchingStrings = + entities + .map { type.matchingStringProvider?.provide(it.getStoringContext()) } + .toSet() + getActivityGroupIds(type, matchingStrings, branchId).forEach { group -> + addToGroup(group.value) + } } } } @@ -36,6 +45,7 @@ class ActivityGrouper( private fun getActivityGroupIds( type: ActivityGroupType, matchingStrings: Set, + branchId: Long?, ): Map { return activityGroupService .getOrCreateCurrentActivityGroupDto( @@ -43,26 +53,10 @@ class ActivityGrouper( matchingStrings, activityRevision.projectId, activityRevision.authorId, + branchId, ).mapValues { it.value.id } } - 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.matchingEntities: List get() { if (!this.sourceActivityTypes.contains(type)) { 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 0c1b4540bc5..a658e00beea 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 @@ -23,6 +23,8 @@ class ActivityGroupsProvider( val pageable: Pageable, val filters: ActivityGroupFilters, applicationContext: ApplicationContext, + val branchId: Long? = null, + val defaultBranchId: Long? = null, ) { fun get(): PageImpl { page.forEach { @@ -36,6 +38,20 @@ class ActivityGroupsProvider( val from = table("activity_group").`as`("ag") var where = field("ag.project_id").eq(projectId) + where = + if (branchId != null) { + where.and(field("ag.branch_id", Long::class.java).eq(branchId)) + } else { + where.and( + field("ag.branch_id", Long::class.java) + .isNull + .or( + defaultBranchId?.let { field("ag.branch_id", Long::class.java).eq(it) } + ?: DSL.noCondition(), + ), + ) + } + var having = DSL.noCondition() val lmeJsonArrayAggField = jsonArrayAgg(field("lme.entity_id")).`as`("lme_entity_ids") @@ -135,10 +151,16 @@ class ActivityGroupsProvider( .flatMap { (type, items) -> val provider = type.modelProviderFactoryClass?.let { applicationContext.getBean(it.java) } - provider?.provideGroup(items.map { it.id })?.map { it.key to it.value } ?: emptyList() + val ids = items.map { it.id } + provider?.provideGroup(ids)?.map { it.key to it.value } + ?: genericGroupModelProvider.provideCounts(type, ids).map { it.key to it.value } }.toMap() } + private val genericGroupModelProvider by lazy { + applicationContext.getBean(io.tolgee.activity.groups.viewProviders.generic.GenericGroupModelProvider::class.java) + } + private val byType by lazy { page.groupBy { it.type } } private val jooqContext = applicationContext.getBean(DSLContext::class.java) 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 c67027611c0..674344de276 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 @@ -16,6 +16,8 @@ class DefaultMatcher( val allowedValues: Map, Any?>? = null, val deniedValues: Map, Any?>? = null, ) : ModifiedEntityMatcher { + override val relevantEntityClasses: Set> = setOf(entityClass) + override fun match(context: StoringContext): Boolean { if (context.modifiedEntity.entityClass != entityClass.simpleName) { return false 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 index ea4bf7266a8..eb9606a4f31 100644 --- 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 @@ -2,14 +2,20 @@ package io.tolgee.activity.groups.matchers.modifiedEntity import org.jooq.Condition import org.jooq.impl.DSL +import kotlin.reflect.KClass interface ModifiedEntityMatcher { + val relevantEntityClasses: Set> + fun match(context: StoringContext): Boolean fun match(context: SqlContext): Condition fun and(other: ModifiedEntityMatcher): ModifiedEntityMatcher { return object : ModifiedEntityMatcher { + override val relevantEntityClasses = + this@ModifiedEntityMatcher.relevantEntityClasses + other.relevantEntityClasses + override fun match(context: StoringContext): Boolean { return this@ModifiedEntityMatcher.match(context) && other.match(context) } @@ -22,6 +28,9 @@ interface ModifiedEntityMatcher { fun or(other: ModifiedEntityMatcher): ModifiedEntityMatcher { return object : ModifiedEntityMatcher { + override val relevantEntityClasses = + this@ModifiedEntityMatcher.relevantEntityClasses + other.relevantEntityClasses + override fun match(context: StoringContext): Boolean { return this@ModifiedEntityMatcher.match(context) || other.match(context) } 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 index ebe73496c30..35129fcab29 100644 --- 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 @@ -4,10 +4,13 @@ import io.tolgee.activity.data.RevisionType import io.tolgee.model.translation.Translation import org.jooq.Condition import org.jooq.impl.DSL +import kotlin.reflect.KClass class TranslationMatcher( private val type: Type = Type.BASE, ) : ModifiedEntityMatcher { + override val relevantEntityClasses: Set> = setOf(Translation::class) + private val defaultMatcher by lazy { DefaultMatcher( entityClass = Translation::class, diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/generic/GenericGroupItemModel.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/generic/GenericGroupItemModel.kt new file mode 100644 index 00000000000..d7359527ad6 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/generic/GenericGroupItemModel.kt @@ -0,0 +1,12 @@ +package io.tolgee.activity.groups.viewProviders.generic + +import io.tolgee.activity.data.EntityDescriptionRef +import io.tolgee.activity.data.PropertyModification + +data class GenericGroupItemModel( + val entityClass: String, + val entityId: Long, + val description: Map, + val describingRelations: Map, + val modifications: Map, +) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/generic/GenericGroupModel.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/generic/GenericGroupModel.kt new file mode 100644 index 00000000000..933da19c0b5 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/generic/GenericGroupModel.kt @@ -0,0 +1,5 @@ +package io.tolgee.activity.groups.viewProviders.generic + +data class GenericGroupModel( + val counts: Map, +) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/generic/GenericGroupModelProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/generic/GenericGroupModelProvider.kt new file mode 100644 index 00000000000..afcf267ee13 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/generic/GenericGroupModelProvider.kt @@ -0,0 +1,63 @@ +package io.tolgee.activity.groups.viewProviders.generic + +import io.tolgee.activity.groups.ActivityGroupType +import io.tolgee.activity.groups.dataProviders.CountsProvider +import io.tolgee.activity.groups.dataProviders.GroupDataProvider +import org.jooq.DSLContext +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.stereotype.Component + +/** + * Group data for group types without a specialized [io.tolgee.activity.groups.GroupModelProvider]: + * per-entity-class counts for the group header and paged raw modified entities for the expanded view. + */ +@Component +class GenericGroupModelProvider( + private val jooqContext: DSLContext, + private val groupDataProvider: GroupDataProvider, +) { + fun provideCounts( + groupType: ActivityGroupType, + groupIds: List, + ): Map { + val entityClasses = groupType.matcher?.relevantEntityClasses ?: return emptyMap() + val counts = + CountsProvider( + jooqContext = jooqContext, + groupType = groupType, + entityClasses = entityClasses.mapNotNull { it.simpleName }, + groupIds = groupIds, + ).provide() + return counts.mapValues { GenericGroupModel(it.value) } + } + + fun provideItems( + groupType: ActivityGroupType, + groupId: Long, + pageable: Pageable, + ): Page { + val entityClass = + groupType.matcher?.relevantEntityClasses?.firstOrNull() + ?: return Page.empty(pageable) + + @Suppress("UNCHECKED_CAST") + val entities = + groupDataProvider.provideRelevantModifiedEntities( + groupType = groupType, + entityClass = entityClass as kotlin.reflect.KClass, + groupId = groupId, + pageable = pageable, + ) + + return entities.map { + GenericGroupItemModel( + entityClass = it.entityClass, + entityId = it.entityId, + description = it.describingData, + describingRelations = it.describingRelations, + modifications = it.modifications, + ) + } + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/iterceptor/ActivityRevisionInitializer.kt b/backend/data/src/main/kotlin/io/tolgee/activity/iterceptor/ActivityRevisionInitializer.kt index 2e52222522c..768e7817906 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/iterceptor/ActivityRevisionInitializer.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/iterceptor/ActivityRevisionInitializer.kt @@ -27,7 +27,7 @@ class ActivityRevisionInitializer( revision.isInitializedByInterceptor = true revision.authorId = userAccount?.id ?: revision.authorId revision.organizationId = organizationId ?: revision.organizationId - revision.projectId = project?.id ?: revision.projectId + project?.let { revision.setProject(it) } revision.type = activityHolder.activity ?: revision.type } 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 f65f1651126..4680967f537 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,6 +1,7 @@ package io.tolgee.model.activity import io.tolgee.activity.groups.ActivityGroupType +import jakarta.persistence.Column import jakarta.persistence.Entity import jakarta.persistence.EnumType import jakarta.persistence.Enumerated @@ -38,6 +39,9 @@ class ActivityGroup( */ var projectId: Long? = null + @Column(name = "branch_id") + var branchId: Long? = null + @ManyToMany(mappedBy = "activityGroups") var activityRevisions: MutableList = mutableListOf() 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 ced07861c26..1438bac13d4 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 @@ -24,6 +24,7 @@ interface ActivityGroupRepository : JpaRepository { AND ag.author_id = :authorId AND ag.type = :groupTypeName AND (ag.matching_string = :matchingString or (:matchingString is null)) + AND ((ag.branch_id = :branchId) or (ag.branch_id is null and :branchId is null)) GROUP BY ag.id order by ag.id desc limit 1 @@ -34,5 +35,6 @@ interface ActivityGroupRepository : JpaRepository { authorId: Long?, projectId: Long?, matchingString: String?, + branchId: 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 e7901710457..0fa5a4dfd86 100644 --- a/backend/data/src/main/resources/db/changelog/schema.xml +++ b/backend/data/src/main/resources/db/changelog/schema.xml @@ -5821,4 +5821,9 @@ + + + + + diff --git a/e2e/cypress/support/dataCyType.d.ts b/e2e/cypress/support/dataCyType.d.ts index 57ea576904f..5ec9fa6bb20 100644 --- a/e2e/cypress/support/dataCyType.d.ts +++ b/e2e/cypress/support/dataCyType.d.ts @@ -19,6 +19,13 @@ declare namespace DataCy { "activity-compact-detail-button": true; "activity-detail": true; "activity-detail-dialog": true; + "activity-group-count": true; + "activity-group-create-key-item": true; + "activity-group-create-project-detail": true; + "activity-group-expand-button": true; + "activity-group-generic-item": true; + "activity-group-item": true; + "activity-groups-list": true; "administration-access-message": true; "administration-debug-customer-account-message": true; "administration-debug-customer-exit-button": true; diff --git a/webapp/src/component/activity/groups/ActivityGroupCard.tsx b/webapp/src/component/activity/groups/ActivityGroupCard.tsx new file mode 100644 index 00000000000..c4afa4daf0a --- /dev/null +++ b/webapp/src/component/activity/groups/ActivityGroupCard.tsx @@ -0,0 +1,115 @@ +import React, { FC, PropsWithChildren, useState } from 'react'; +import { Box, Chip, IconButton, styled } from '@mui/material'; +import { ChevronDown, ChevronUp } from '@untitled-ui/icons-react'; + +import { components } from 'tg.service/apiSchema.generated'; +import { AvatarImg } from 'tg.component/common/avatar/AvatarImg'; +import { useDateFormatter } from 'tg.hooks/useLocale'; + +type ActivityGroupModel = components['schemas']['ActivityGroupModel']; + +const StyledContainer = styled('div')` + display: grid; + gap: 8px 12px; + padding: 12px 16px; + border-radius: 12px; + background: ${({ theme }) => theme.palette.background.paper}; + border: 1px solid ${({ theme }) => theme.palette.divider}; + grid-template-columns: auto 1fr auto auto; + grid-template-areas: + 'avatar content time expand' + 'expanded expanded expanded expanded'; + align-items: center; +`; + +const StyledContent = styled(Box)` + grid-area: content; + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 4px 8px; + min-width: 0; +`; + +const StyledAuthor = styled(Box)` + font-weight: 500; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +`; + +const StyledTime = styled(Box)` + grid-area: time; + font-size: 12px; + color: ${({ theme }) => theme.palette.text.secondary}; + white-space: nowrap; +`; + +const StyledExpanded = styled(Box)` + grid-area: expanded; + overflow-x: auto; +`; + +type Props = PropsWithChildren<{ + item: ActivityGroupModel; + count?: number; + expandedContent?: React.ReactNode; +}>; + +export const ActivityGroupCard: FC = (props) => { + const [expanded, setExpanded] = useState(false); + const formatDate = useDateFormatter(); + + const author = props.item.author; + + return ( + + + {author && ( + + )} + + + {author?.name || author?.username} + {props.children} + {props.count !== undefined && props.count > 0 && ( + + )} + + + {formatDate(new Date(props.item.timestamp), { + dateStyle: 'medium', + timeStyle: 'short', + })} + + + {props.expandedContent !== undefined && ( + setExpanded(!expanded)} + > + {expanded ? : } + + )} + + {expanded && {props.expandedContent}} + + ); +}; diff --git a/webapp/src/component/activity/groups/ActivityGroupItem.tsx b/webapp/src/component/activity/groups/ActivityGroupItem.tsx index fbae684cbb1..aff52f0e3fd 100644 --- a/webapp/src/component/activity/groups/ActivityGroupItem.tsx +++ b/webapp/src/component/activity/groups/ActivityGroupItem.tsx @@ -1,23 +1,68 @@ 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'; -import { SetTranslationsActivityGroup } from './groupTypeComponents/SetTranslationsActivityGroup'; +import { ActivityGroupCard } from './ActivityGroupCard'; +import { GenericGroupExpandedContent } from './GenericGroupExpandedContent'; +import { CreateKeysExpandedContent } from './groupTypeComponents/CreateKeysActivityGroup'; +import { CreateProjectExpandedContent } from './groupTypeComponents/CreateProjectActivityGroup'; +import { groupsConfiguration } from './groupsConfiguration'; + +type ActivityGroupModel = components['schemas']['ActivityGroupModel']; export const ActivityGroupItem: FC<{ - item: components['schemas']['ActivityGroupModel']; -}> = (props) => { - switch (props.item.type) { + item: ActivityGroupModel; +}> = ({ item }) => { + const label = groupsConfiguration[item.type]?.label ?? item.type; + const data = ('data' in item ? item.data : undefined) as + | Record + | undefined; + + switch (item.type) { case 'CREATE_PROJECT': - return ; + return ( + } + > + {label} + + ); case 'CREATE_KEY': - return ; + return ( + } + > + {label} + + ); case 'SET_TRANSLATIONS': - return ; + return ( + } + > + {label} + + ); default: return ( - {props.item.type} + } + > + {label} + ); } }; + +function sumCounts(data: Record | undefined): number | undefined { + const counts = data?.counts as Record | undefined; + if (!counts) { + return undefined; + } + return Object.values(counts).reduce((a, b) => a + b, 0); +} diff --git a/webapp/src/component/activity/groups/GenericGroupExpandedContent.tsx b/webapp/src/component/activity/groups/GenericGroupExpandedContent.tsx new file mode 100644 index 00000000000..03f59d245b6 --- /dev/null +++ b/webapp/src/component/activity/groups/GenericGroupExpandedContent.tsx @@ -0,0 +1,72 @@ +import React, { FC, useState } from 'react'; +import { + Table, + TableBody, + TableCell, + TableHead, + TableRow, +} from '@mui/material'; + +import { useApiQuery } from 'tg.service/http/useQueryApi'; +import { useProject } from 'tg.hooks/useProject'; +import { PaginatedHateoasList } from 'tg.component/common/list/PaginatedHateoasList'; +import { components } from 'tg.service/apiSchema.generated'; + +type GenericGroupItemModel = components['schemas']['GenericGroupItemModel']; + +const DISPLAYED_DESCRIPTION_FIELDS = ['name', 'text', 'key', 'tag', 'username']; + +export const GenericGroupExpandedContent: FC<{ groupId: number }> = (props) => { + const project = useProject(); + const [page, setPage] = useState(0); + + const loadable = useApiQuery({ + url: '/v2/projects/{projectId}/activity/group-items/generic/{groupId}', + method: 'get', + path: { projectId: project.id, groupId: props.groupId }, + query: { page, size: 20 }, + }); + + return ( + setPage(p)} + listComponent={ItemsTable} + renderItem={(item: GenericGroupItemModel) => ( + + {item.entityClass} + {describe(item)} + {modificationSummary(item)} + + )} + /> + ); +}; + +const ItemsTable: FC = (props) => ( +
+ + + + + + + + {props.children} +
+); + +function describe(item: GenericGroupItemModel): string { + for (const field of DISPLAYED_DESCRIPTION_FIELDS) { + const value = item.description?.[field]; + if (typeof value === 'string' && value) { + return value; + } + } + return `#${item.entityId}`; +} + +function modificationSummary(item: GenericGroupItemModel): string { + const mods = item.modifications || {}; + return Object.keys(mods).join(', '); +} diff --git a/webapp/src/component/activity/groups/SimpleTableExpandedContent.tsx b/webapp/src/component/activity/groups/SimpleTableExpandedContent.tsx deleted file mode 100644 index fdd3152d971..00000000000 --- a/webapp/src/component/activity/groups/SimpleTableExpandedContent.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import React, { FC, PropsWithChildren } 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> = (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/CollapsibleActivityGroup.tsx b/webapp/src/component/activity/groups/groupTypeComponents/CollapsibleActivityGroup.tsx deleted file mode 100644 index 07b68117653..00000000000 --- a/webapp/src/component/activity/groups/groupTypeComponents/CollapsibleActivityGroup.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React, { FC, PropsWithChildren } from 'react'; -import { Box, Button } from '@mui/material'; - -export const CollapsibleActivityGroup: FC< - PropsWithChildren<{ - 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 index 3aeee93c5de..599b9abcef7 100644 --- a/webapp/src/component/activity/groups/groupTypeComponents/CreateKeysActivityGroup.tsx +++ b/webapp/src/component/activity/groups/groupTypeComponents/CreateKeysActivityGroup.tsx @@ -1,37 +1,61 @@ -import React, { FC } from 'react'; -import { components } from 'tg.service/apiSchema.generated'; -import { CollapsibleActivityGroup } from './CollapsibleActivityGroup'; +import React, { FC, useState } from 'react'; +import { + Table, + TableBody, + TableCell, + TableHead, + TableRow, +} from '@mui/material'; +import { T } from '@tolgee/react'; + import { useApiQuery } from 'tg.service/http/useQueryApi'; import { useProject } from 'tg.hooks/useProject'; -import { SimpleTableExpandedContent } from '../SimpleTableExpandedContent'; - -type Group = components['schemas']['ActivityGroupCreateKeyModel']; +import { PaginatedHateoasList } from 'tg.component/common/list/PaginatedHateoasList'; +import { components } from 'tg.service/apiSchema.generated'; -export const CreateKeysActivityGroup: FC<{ - group: Group; -}> = ({ group }) => { - return ( - } - > - {group.author?.name} Created {group.data?.keyCount} keys{' '} - - ); -}; +type CreateKeyGroupItemModel = components['schemas']['CreateKeyGroupItemModel']; -const ExpandedContent: FC<{ group: Group }> = (props) => { +export const CreateKeysExpandedContent: FC<{ groupId: number }> = (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, - }, - }); + const [page, setPage] = useState(0); + + const loadable = useApiQuery({ + url: '/v2/projects/{projectId}/activity/group-items/create-key/{groupId}', + method: 'get', + path: { projectId: project.id, groupId: props.groupId }, + query: { page, size: 20 }, + }); + return ( - + setPage(p)} + listComponent={KeysTable} + renderItem={(item: CreateKeyGroupItemModel) => ( + + {item.name} + {item.baseTranslationText ?? ''} + + )} + /> ); }; + +const KeysTable: FC = (props) => ( + + + + + + + + + + + + {props.children} +
+); diff --git a/webapp/src/component/activity/groups/groupTypeComponents/CreateProjectActivityGroup.tsx b/webapp/src/component/activity/groups/groupTypeComponents/CreateProjectActivityGroup.tsx index 5409b4efd26..6f92a9eb39b 100644 --- a/webapp/src/component/activity/groups/groupTypeComponents/CreateProjectActivityGroup.tsx +++ b/webapp/src/component/activity/groups/groupTypeComponents/CreateProjectActivityGroup.tsx @@ -1,21 +1,37 @@ import React, { FC } from 'react'; -import { components } from 'tg.service/apiSchema.generated'; -import { CollapsibleActivityGroup } from './CollapsibleActivityGroup'; +import { Box, styled } from '@mui/material'; -type Group = components['schemas']['ActivityGroupCreateProjectModel']; +import { CircledLanguageIcon } from 'tg.component/languages/CircledLanguageIcon'; + +const StyledLanguages = styled(Box)` + display: flex; + gap: 8px; + align-items: center; + flex-wrap: wrap; + padding: 8px 0; +`; + +export const CreateProjectExpandedContent: FC<{ + data: Record | undefined; +}> = ({ data }) => { + const languages = (data?.languages || []) as { + id: number; + name: string; + tag: string; + flagEmoji: string; + }[]; -export const CreateProjectActivityGroup: FC<{ - group: Group; -}> = ({ group }) => { return ( - } - > - {group.author?.name} Created project {group.data?.name} - + + {data?.name} + + {languages.map((language) => ( + + + {language.name} + + ))} + + ); }; - -const ExpandedContent: FC<{ group: Group }> = (props) => { - return
{JSON.stringify(props.group, null, 2)}
; -}; diff --git a/webapp/src/component/activity/groups/groupTypeComponents/SetTranslationsActivityGroup.tsx b/webapp/src/component/activity/groups/groupTypeComponents/SetTranslationsActivityGroup.tsx deleted file mode 100644 index 568db378b32..00000000000 --- a/webapp/src/component/activity/groups/groupTypeComponents/SetTranslationsActivityGroup.tsx +++ /dev/null @@ -1,35 +0,0 @@ -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/component/activity/groups/groupsConfiguration.tsx b/webapp/src/component/activity/groups/groupsConfiguration.tsx new file mode 100644 index 00000000000..3f667437a5a --- /dev/null +++ b/webapp/src/component/activity/groups/groupsConfiguration.tsx @@ -0,0 +1,626 @@ +import React from 'react'; +import { T } from '@tolgee/react'; +import { components } from 'tg.service/apiSchema.generated'; + +type ActivityGroupTypeEnum = + components['schemas']['ActivityGroupModel']['type']; + +type GroupTypeConfiguration = { + label: React.ReactNode; +}; + +export const groupsConfiguration: Record< + ActivityGroupTypeEnum, + GroupTypeConfiguration +> = { + CREATE_KEY: { + label: ( + + ), + }, + EDIT_KEY_NAME: { + label: ( + + ), + }, + DELETE_KEY: { + label: ( + + ), + }, + SET_TRANSLATION_STATE: { + label: ( + + ), + }, + REVIEW: { + label: ( + + ), + }, + SET_BASE_TRANSLATION: { + label: ( + + ), + }, + SET_TRANSLATIONS: { + label: ( + + ), + }, + DISMISS_AUTO_TRANSLATED_STATE: { + label: ( + + ), + }, + SET_OUTDATED_FLAG: { + label: ( + + ), + }, + ADD_TRANSLATION_COMMENT: { + label: ( + + ), + }, + DELETE_TRANSLATION_COMMENT: { + label: ( + + ), + }, + EDIT_TRANSLATION_COMMENT: { + label: ( + + ), + }, + SET_TRANSLATION_COMMENT_STATE: { + label: ( + + ), + }, + DELETE_SCREENSHOT: { + label: ( + + ), + }, + ADD_SCREENSHOT: { + label: ( + + ), + }, + EDIT_KEY_TAGS: { + label: ( + + ), + }, + IMPORT: { + label: ( + + ), + }, + CREATE_LANGUAGE: { + label: ( + + ), + }, + EDIT_LANGUAGE: { + label: ( + + ), + }, + DELETE_LANGUAGE: { + label: ( + + ), + }, + CREATE_PROJECT: { + label: ( + + ), + }, + EDIT_PROJECT: { + label: ( + + ), + }, + NAMESPACE_EDIT: { + label: ( + + ), + }, + BATCH_PRE_TRANSLATE_BY_TM: { + label: ( + + ), + }, + BATCH_MACHINE_TRANSLATE: { + label: ( + + ), + }, + AUTO_TRANSLATE: { + label: ( + + ), + }, + BATCH_CLEAR_TRANSLATIONS: { + label: ( + + ), + }, + BATCH_COPY_TRANSLATIONS: { + label: ( + + ), + }, + BATCH_SET_TRANSLATION_STATE: { + label: ( + + ), + }, + CONTENT_DELIVERY_CONFIG_CREATE: { + label: ( + + ), + }, + CONTENT_DELIVERY_CONFIG_UPDATE: { + label: ( + + ), + }, + CONTENT_DELIVERY_CONFIG_DELETE: { + label: ( + + ), + }, + CONTENT_STORAGE_CREATE: { + label: ( + + ), + }, + CONTENT_STORAGE_UPDATE: { + label: ( + + ), + }, + CONTENT_STORAGE_DELETE: { + label: ( + + ), + }, + WEBHOOK_CONFIG_CREATE: { + label: ( + + ), + }, + WEBHOOK_CONFIG_UPDATE: { + label: ( + + ), + }, + WEBHOOK_CONFIG_DELETE: { + label: ( + + ), + }, + EDIT_KEY_CHARACTER_LIMIT: { + label: ( + + ), + }, + SOFT_DELETE_KEY: { + label: ( + + ), + }, + RESTORE_KEY: { + label: ( + + ), + }, + HARD_DELETE_KEY: { + label: ( + + ), + }, + SET_TRANSLATION_LABELS: { + label: ( + + ), + }, + CREATE_TRANSLATION_LABEL: { + label: ( + + ), + }, + EDIT_TRANSLATION_LABEL: { + label: ( + + ), + }, + DELETE_TRANSLATION_LABEL: { + label: ( + + ), + }, + CREATE_TASK: { + label: ( + + ), + }, + EDIT_TASK: { + label: ( + + ), + }, + FINISH_TASK: { + label: ( + + ), + }, + CLOSE_TASK: { + label: ( + + ), + }, + REOPEN_TASK: { + label: ( + + ), + }, + UPDATE_TASK_KEYS: { + label: ( + + ), + }, + CREATE_GLOSSARY: { + label: ( + + ), + }, + EDIT_GLOSSARY: { + label: ( + + ), + }, + DELETE_GLOSSARY: { + label: ( + + ), + }, + IMPORT_GLOSSARY: { + label: ( + + ), + }, + CREATE_GLOSSARY_TERM: { + label: ( + + ), + }, + EDIT_GLOSSARY_TERM: { + label: ( + + ), + }, + DELETE_GLOSSARY_TERM: { + label: ( + + ), + }, + SET_GLOSSARY_TERM_TRANSLATION: { + label: ( + + ), + }, + CREATE_TRANSLATION_MEMORY: { + label: ( + + ), + }, + EDIT_TRANSLATION_MEMORY: { + label: ( + + ), + }, + DELETE_TRANSLATION_MEMORY: { + label: ( + + ), + }, + CREATE_SUGGESTION: { + label: ( + + ), + }, + DELETE_SUGGESTION: { + label: ( + + ), + }, + DECLINE_SUGGESTION: { + label: ( + + ), + }, + ACCEPT_SUGGESTION: { + label: ( + + ), + }, + SET_SUGGESTION_ACTIVE: { + label: ( + + ), + }, + CREATE_AI_PROMPT: { + label: ( + + ), + }, + EDIT_AI_PROMPT: { + label: ( + + ), + }, + DELETE_AI_PROMPT: { + label: ( + + ), + }, + CREATE_BRANCH: { + label: ( + + ), + }, + RENAME_BRANCH: { + label: ( + + ), + }, + CHANGE_BRANCH_PROTECTION: { + label: ( + + ), + }, + MERGE_BRANCH: { + label: ( + + ), + }, + IGNORE_QA_ISSUE: { + label: ( + + ), + }, + UNIGNORE_QA_ISSUE: { + label: ( + + ), + }, +}; diff --git a/webapp/src/i18n/en.json b/webapp/src/i18n/en.json index 1230f4438f4..ed7dfaf0f6f 100644 --- a/webapp/src/i18n/en.json +++ b/webapp/src/i18n/en.json @@ -52,6 +52,85 @@ "active-plan-license-key-button": "Show license key", "active-plan-license-key-caption": "Apply this license key in your local Tolgee instance", "active-plan-subscribed-at-tooltip": "Subscribed at", + "activity_groups_base_translation_column": "Base translation", + "activity_groups_key_name_column": "Key", + "activity_groups_type_accept_suggestion": "Accepted suggestions", + "activity_groups_type_add_screenshot": "Added screenshots", + "activity_groups_type_add_translation_comment": "Added translation comments", + "activity_groups_type_auto_translate": "Auto-translated", + "activity_groups_type_batch_clear_translations": "Cleared translations", + "activity_groups_type_batch_copy_translations": "Copied translations", + "activity_groups_type_batch_machine_translate": "Machine translated", + "activity_groups_type_batch_pre_translate_by_tm": "Pre-translated by translation memory", + "activity_groups_type_batch_set_translation_state": "Changed translation states in batch", + "activity_groups_type_change_branch_protection": "Changed branch protection", + "activity_groups_type_close_task": "Closed tasks", + "activity_groups_type_content_delivery_config_create": "Created content delivery configurations", + "activity_groups_type_content_delivery_config_delete": "Deleted content delivery configurations", + "activity_groups_type_content_delivery_config_update": "Updated content delivery configurations", + "activity_groups_type_content_storage_create": "Created content storages", + "activity_groups_type_content_storage_delete": "Deleted content storages", + "activity_groups_type_content_storage_update": "Updated content storages", + "activity_groups_type_create_ai_prompt": "Created AI prompts", + "activity_groups_type_create_branch": "Created branches", + "activity_groups_type_create_glossary": "Created glossaries", + "activity_groups_type_create_glossary_term": "Created glossary terms", + "activity_groups_type_create_key": "Created keys", + "activity_groups_type_create_language": "Created languages", + "activity_groups_type_create_project": "Created the project", + "activity_groups_type_create_suggestion": "Created suggestions", + "activity_groups_type_create_task": "Created tasks", + "activity_groups_type_create_translation_label": "Created labels", + "activity_groups_type_create_translation_memory": "Created translation memories", + "activity_groups_type_decline_suggestion": "Declined suggestions", + "activity_groups_type_delete_ai_prompt": "Deleted AI prompts", + "activity_groups_type_delete_glossary": "Deleted glossaries", + "activity_groups_type_delete_glossary_term": "Deleted glossary terms", + "activity_groups_type_delete_key": "Deleted keys", + "activity_groups_type_delete_language": "Deleted languages", + "activity_groups_type_delete_screenshot": "Deleted screenshots", + "activity_groups_type_delete_suggestion": "Deleted suggestions", + "activity_groups_type_delete_translation_comment": "Deleted translation comments", + "activity_groups_type_delete_translation_label": "Deleted labels", + "activity_groups_type_delete_translation_memory": "Deleted translation memories", + "activity_groups_type_dismiss_auto_translated_state": "Dismissed auto-translated states", + "activity_groups_type_edit_ai_prompt": "Edited AI prompts", + "activity_groups_type_edit_glossary": "Edited glossaries", + "activity_groups_type_edit_glossary_term": "Edited glossary terms", + "activity_groups_type_edit_key_character_limit": "Changed key character limits", + "activity_groups_type_edit_key_name": "Renamed keys", + "activity_groups_type_edit_key_tags": "Edited key tags", + "activity_groups_type_edit_language": "Edited languages", + "activity_groups_type_edit_project": "Edited project settings", + "activity_groups_type_edit_task": "Edited tasks", + "activity_groups_type_edit_translation_comment": "Edited translation comments", + "activity_groups_type_edit_translation_label": "Edited labels", + "activity_groups_type_edit_translation_memory": "Edited translation memories", + "activity_groups_type_finish_task": "Finished tasks", + "activity_groups_type_hard_delete_key": "Permanently deleted keys", + "activity_groups_type_ignore_qa_issue": "Ignored QA issues", + "activity_groups_type_import": "Imported data", + "activity_groups_type_import_glossary": "Imported glossaries", + "activity_groups_type_merge_branch": "Merged branches", + "activity_groups_type_namespace_edit": "Edited namespaces", + "activity_groups_type_rename_branch": "Renamed branches", + "activity_groups_type_reopen_task": "Reopened tasks", + "activity_groups_type_restore_key": "Restored keys", + "activity_groups_type_review": "Reviewed translations", + "activity_groups_type_set_base_translation": "Changed base translations", + "activity_groups_type_set_glossary_term_translation": "Set glossary term translations", + "activity_groups_type_set_outdated_flag": "Changed outdated flags", + "activity_groups_type_set_suggestion_active": "Reactivated suggestions", + "activity_groups_type_set_translations": "Set translations", + "activity_groups_type_set_translation_comment_state": "Changed translation comment states", + "activity_groups_type_set_translation_labels": "Changed translation labels", + "activity_groups_type_set_translation_state": "Changed translation states", + "activity_groups_type_soft_delete_key": "Moved keys to trash", + "activity_groups_type_unignore_qa_issue": "Reopened QA issues", + "activity_groups_type_update_task_keys": "Updated task keys", + "activity_groups_type_webhook_config_create": "Created webhook configurations", + "activity_groups_type_webhook_config_delete": "Deleted webhook configurations", + "activity_groups_type_webhook_config_update": "Updated webhook configurations", "activity_accept_suggestion": "Accepted suggestion", "activity_batch_key_hard_delete": "{KeyCount, plural, one {Permanently deleted 1 key} other {Permanently deleted # key}}", "activity_batch_key_restore": "{KeyCount, plural, one {Restored 1 key} other {Restored # keys}}", diff --git a/webapp/src/service/apiSchema.generated.ts b/webapp/src/service/apiSchema.generated.ts index 8b62c7b8f8f..603e13e4424 100644 --- a/webapp/src/service/apiSchema.generated.ts +++ b/webapp/src/service/apiSchema.generated.ts @@ -430,6 +430,10 @@ export interface paths { "/v2/projects/{projectId}/activity/group-items/create-key/{groupId}": { get: operations["getCreateKeyItems"]; }; + "/v2/projects/{projectId}/activity/group-items/generic/{groupId}": { + /** Returns the modified entities of the group as generic items (any group type). */ + get: operations["getGenericItems"]; + }; "/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"]; @@ -4424,6 +4428,11 @@ export interface components { | "KEY_USED_BY_ANOTHER_INSTANCE" | "UNKNOWN"; }; + EntityDescriptionRef: { + entityClass: string; + /** Format: int64 */ + entityId: number; + }; EntityDescriptionWithRelations: { data: { [key: string]: unknown }; entityClass: string; @@ -4943,6 +4952,18 @@ export interface components { name: string; oldSlug?: string; }; + GenericGroupItemModel: { + describingRelations: { + [key: string]: components["schemas"]["EntityDescriptionRef"]; + }; + description: { [key: string]: unknown }; + entityClass: string; + /** Format: int64 */ + entityId: number; + modifications: { + [key: string]: components["schemas"]["PropertyModification"]; + }; + }; GetKeysRequestDto: { keys: components["schemas"]["KeyDefinitionDto"][]; /** @description Tags to return language translations in */ @@ -6235,6 +6256,12 @@ export interface components { }; page?: components["schemas"]["PageMetadata"]; }; + PagedModelGenericGroupItemModel: { + _embedded?: { + genericGroupItemModelList?: components["schemas"]["GenericGroupItemModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; PagedModelImportFileIssueModel: { _embedded?: { importFileIssues?: components["schemas"]["ImportFileIssueModel"][]; @@ -15291,6 +15318,55 @@ export interface operations { }; }; }; + /** Returns the modified entities of the group as generic items (any group type). */ + getGenericItems: { + 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"]["PagedModelGenericGroupItemModel"]; + }; + }; + /** Bad Request */ + 400: { + content: { + "application/json": string; + }; + }; + /** Unauthorized */ + 401: { + content: { + "application/json": string; + }; + }; + /** Forbidden */ + 403: { + content: { + "application/json": string; + }; + }; + /** Not Found */ + 404: { + content: { + "application/json": string; + }; + }; + }; + }; /** This endpoints returns the activity grouped by time windows so it's easier to read on the frontend. */ getActivityGroups: { parameters: { @@ -15381,6 +15457,7 @@ export interface operations { | "UNIGNORE_QA_ISSUE"; filterLanguageIdIn?: number[]; filterAuthorUserIdIn?: number[]; + branch?: string; }; path: { projectId: number; diff --git a/webapp/src/service/apiSchemaTypes.generated.ts b/webapp/src/service/apiSchemaTypes.generated.ts index abc13fb2c50..28d0e397792 100644 --- a/webapp/src/service/apiSchemaTypes.generated.ts +++ b/webapp/src/service/apiSchemaTypes.generated.ts @@ -187,6 +187,7 @@ export type DryRunMergeBranchRequest = components['schemas']['DryRunMergeBranchR export type EditKeyDto = components['schemas']['EditKeyDto']; export type EditProjectRequest = components['schemas']['EditProjectRequest']; export type EeSubscriptionModel = components['schemas']['EeSubscriptionModel']; +export type EntityDescriptionRef = components['schemas']['EntityDescriptionRef']; export type EntityDescriptionWithRelations = components['schemas']['EntityDescriptionWithRelations']; export type ErrorResponseBody = components['schemas']['ErrorResponseBody']; export type ErrorResponseTyped = components['schemas']['ErrorResponseTyped']; @@ -194,6 +195,7 @@ export type ExistenceEntityDescription = components['schemas']['ExistenceEntityD export type ExportFormatModel = components['schemas']['ExportFormatModel']; export type ExportParams = components['schemas']['ExportParams']; export type GenerateSlugDto = components['schemas']['GenerateSlugDto']; +export type GenericGroupItemModel = components['schemas']['GenericGroupItemModel']; export type GetKeysRequestDto = components['schemas']['GetKeysRequestDto']; export type GlossaryHighlightsRequest = components['schemas']['GlossaryHighlightsRequest']; export type GlossaryImportResult = components['schemas']['GlossaryImportResult']; @@ -292,6 +294,7 @@ export type PagedModelBranchModel = components['schemas']['PagedModelBranchModel export type PagedModelContentDeliveryConfigModel = components['schemas']['PagedModelContentDeliveryConfigModel']; export type PagedModelContentStorageModel = components['schemas']['PagedModelContentStorageModel']; export type PagedModelCreateKeyGroupItemModel = components['schemas']['PagedModelCreateKeyGroupItemModel']; +export type PagedModelGenericGroupItemModel = components['schemas']['PagedModelGenericGroupItemModel']; export type PagedModelImportFileIssueModel = components['schemas']['PagedModelImportFileIssueModel']; export type PagedModelImportLanguageModel = components['schemas']['PagedModelImportLanguageModel']; export type PagedModelImportTranslationModel = components['schemas']['PagedModelImportTranslationModel']; diff --git a/webapp/src/views/projects/ActivityView.tsx b/webapp/src/views/projects/ActivityView.tsx index 04d4242c73c..6a801bb0914 100644 --- a/webapp/src/views/projects/ActivityView.tsx +++ b/webapp/src/views/projects/ActivityView.tsx @@ -1,4 +1,7 @@ +import React from 'react'; +import { Box, styled } from '@mui/material'; import { useTranslate } from '@tolgee/react'; + import { BaseProjectView } from './BaseProjectView'; import { useApiQuery } from 'tg.service/http/useQueryApi'; import { useProject } from 'tg.hooks/useProject'; @@ -6,25 +9,34 @@ import { PaginatedHateoasList } from 'tg.component/common/list/PaginatedHateoasL import { ActivityGroupItem } from 'tg.component/activity/groups/ActivityGroupItem'; import { ProjectLanguagesProvider } from 'tg.hooks/ProjectLanguagesProvider'; +const StyledList = styled(Box)` + display: grid; + gap: 8px; + padding-top: 16px; +`; + export const ActivityView = () => { const { t } = useTranslate(); - const project = useProject(); + const [page, setPage] = React.useState(0); const groupsLoadable = useApiQuery({ url: '/v2/projects/{projectId}/activity/groups', method: 'get', path: { projectId: project.id }, - query: {}, + query: { page, size: 20, sort: ['id,desc'] }, }); return ( - + - } - /> + + setPage(p)} + renderItem={(item) => } + /> + ); From 0587adca00aa6ed40ca61fd520dfe03cbadfe4f9 Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Sat, 11 Jul 2026 19:04:17 +0200 Subject: [PATCH 50/57] fix: stable identity keys for pre-allocation modified entities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Entity hashCode is id-based and mutates when the id gets assigned, stranding instance-keyed map entries in stale hash buckets — the same row was then recorded again under its id key, breaking activity inserts with duplicate PKs (project stats, history, language deletion, usage reporting tests). Key such entries by an EntityIdentity wrapper with identity hashCode and migrate them to the id key once the id is known. Also restore main's expected decimal formats in ProjectsControllerTest. --- .../ProjectsControllerTest.kt | 2 +- .../io/tolgee/activity/ActivityHolder.kt | 24 +++++++++++++++---- .../iterceptor/InterceptedEventsManager.kt | 5 ++-- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/ProjectsControllerTest.kt b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/ProjectsControllerTest.kt index 0b0cd1177a6..49262f0df71 100644 --- a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/ProjectsControllerTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/ProjectsControllerTest.kt @@ -102,7 +102,7 @@ class ProjectsControllerTest : ProjectAuthControllerTest("/v2/projects/") { { "UNTRANSLATED": 25.0, "TRANSLATED": 75.0, - "REVIEWED": 0 + "REVIEWED": 0.0 } """, ) 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 6dad59d79f2..4bc69231617 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/ActivityHolder.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/ActivityHolder.kt @@ -98,20 +98,34 @@ open class ActivityHolder( } /** - * Inner map key is the entity id when it's already allocated, otherwise the entity - * instance itself (some ids are only assigned later in the transaction). Keying purely - * by instance would record the same row twice when Hibernate yields multiple instances - * of it in one transaction (e.g. after an entityManager.clear()). + * Inner map key is the entity id when it's already allocated, otherwise an + * [EntityIdentity] of the instance (some ids are only assigned later in the + * transaction). Keying purely by instance would record the same row twice when + * Hibernate yields multiple instances of it in one transaction (e.g. after an + * entityManager.clear()). */ typealias ModifiedEntitiesType = MutableMap, MutableMap> +/** + * Identity-based key for entities whose id is not allocated yet. Entity hashCode + * is id-based and mutates when the id gets assigned, which would strand the map + * entry in a stale hash bucket. + */ +class EntityIdentity( + val entity: EntityWithId, +) { + override fun hashCode() = System.identityHashCode(entity) + + override fun equals(other: Any?) = other is EntityIdentity && other.entity === entity +} + val Map.Entry.resolvedEntityId: Long get() { val key = key return when { key is Long -> key - key is EntityWithId && key.id != 0L -> key.id + key is EntityIdentity && key.entity.id != 0L -> key.entity.id else -> value.entityId } } 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 50c5b40da33..fa58d92ccfd 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 @@ -2,6 +2,7 @@ package io.tolgee.activity.iterceptor import io.tolgee.activity.ActivityService import io.tolgee.activity.EntityDescriptionProvider +import io.tolgee.activity.EntityIdentity import io.tolgee.activity.annotation.ActivityIgnoredProp import io.tolgee.activity.annotation.ActivityLoggedEntity import io.tolgee.activity.annotation.ActivityLoggedProp @@ -204,14 +205,14 @@ class InterceptedEventsManager( val classMap = activityHolder.modifiedEntities.computeIfAbsent(entity::class) { mutableMapOf() } if (entity.id != 0L) { // the entity may have been recorded before its id was allocated - classMap.remove(entity)?.let { + classMap.remove(EntityIdentity(entity))?.let { it.entityId = entity.id classMap.putIfAbsent(entity.id, it) } } val activityModifiedEntity = classMap.computeIfAbsent( - if (entity.id != 0L) entity.id else entity, + if (entity.id != 0L) entity.id else EntityIdentity(entity), ) { ActivityModifiedEntity( activityRevision, From 5c0095373b64090d19d6c6a8f30583a879f74a7c Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Sat, 11 Jul 2026 19:54:04 +0200 Subject: [PATCH 51/57] feat: show grouped activity on the project dashboard Replace the per-revision ActivityCompact list with the grouped activity cards (infinite scroll over /activity/groups, date separators kept). The date separator now spans all implicit columns instead of the removed 3-column grid. Dashboard e2e spec asserts group cards and expanded create-key items instead of compact rows and the detail dialog. --- .../e2e/projects/projectDashboard.cy.ts | 48 ++---- .../dashboard/ActivityDateSeparator.tsx | 2 +- .../projects/dashboard/ActivityGroupsList.tsx | 101 ++++++++++++ .../views/projects/dashboard/ActivityList.tsx | 151 ------------------ .../projects/dashboard/DashboardView.tsx | 6 +- 5 files changed, 121 insertions(+), 187 deletions(-) create mode 100644 webapp/src/views/projects/dashboard/ActivityGroupsList.tsx delete mode 100644 webapp/src/views/projects/dashboard/ActivityList.tsx diff --git a/e2e/cypress/e2e/projects/projectDashboard.cy.ts b/e2e/cypress/e2e/projects/projectDashboard.cy.ts index c68d96ab706..5e36eeb5d2c 100644 --- a/e2e/cypress/e2e/projects/projectDashboard.cy.ts +++ b/e2e/cypress/e2e/projects/projectDashboard.cy.ts @@ -3,7 +3,7 @@ import { projectListData } from '../../common/apiCalls/testData/testData'; import { createComment, resolveComment } from '../../common/comments'; import { HOST } from '../../common/constants'; import { createProject, enterProject } from '../../common/projects'; -import { gcy, selectInProjectMenu } from '../../common/shared'; +import { gcy, gcyAdvanced, selectInProjectMenu } from '../../common/shared'; import { getCell } from '../../common/state'; import { createTag } from '../../common/tags'; import { createTranslation } from '../../common/translations'; @@ -35,31 +35,20 @@ describe('Project stats', () => { selectInProjectMenu('Project Dashboard'); - cy.gcy('activity-compact') - .contains('Comment state change') + assertGroupVisible('SET_TRANSLATION_COMMENT_STATE'); + assertGroupVisible('ADD_TRANSLATION_COMMENT'); + assertGroupVisible('REVIEW'); + assertGroupVisible('EDIT_KEY_TAGS'); + assertGroupVisible('CREATE_KEY'); + assertGroupVisible('CREATE_PROJECT'); + + // expandable group detail + gcyAdvanced({ value: 'activity-group-item', type: 'CREATE_KEY' }) + .findDcy('activity-group-expand-button') + .click(); + cy.gcy('activity-group-create-key-item') + .contains('new translation') .should('be.visible'); - cy.gcy('activity-compact').contains('Added comment').should('be.visible'); - cy.gcy('activity-compact') - .contains('Set translation state') - .should('be.visible'); - cy.gcy('activity-compact') - .contains('Key tags updated') - .should('be.visible'); - cy.gcy('activity-compact').contains('Created key').should('be.visible'); - cy.gcy('activity-compact').contains('Created project').should('be.visible'); - - openActivityDetail('Created key'); - - // activity is accessible through external link - cy.url().then((url) => { - const activityId = new URL(url).searchParams.get('activity'); - const projectId = new URL(url).pathname.match(/[0-9]+/)[0]; - cy.visit( - HOST + `/projects/${projectId}/activity-detail?activity=${activityId}` - ); - cy.waitForDom(); - cy.gcy('activity-detail-dialog').contains('Created key'); - }); }); it('Global statistics', () => { @@ -100,13 +89,8 @@ describe('Project stats', () => { }); }); -const openActivityDetail = (label: string) => { - cy.gcy('activity-compact') - .contains(label) - .closestDcy('activity-compact') - .findDcy('activity-compact-detail-button') - .click({ force: true }); - cy.gcy('activity-detail-dialog').contains(label); +const assertGroupVisible = (type: string) => { + gcyAdvanced({ value: 'activity-group-item', type }).should('be.visible'); }; const checkLabelRow = ( diff --git a/webapp/src/views/projects/dashboard/ActivityDateSeparator.tsx b/webapp/src/views/projects/dashboard/ActivityDateSeparator.tsx index 0bad142a1eb..c77408155e5 100644 --- a/webapp/src/views/projects/dashboard/ActivityDateSeparator.tsx +++ b/webapp/src/views/projects/dashboard/ActivityDateSeparator.tsx @@ -3,7 +3,7 @@ import { useTranslate } from '@tolgee/react'; import { useCurrentLanguage } from '@tginternal/library/hooks/useCurrentLanguage'; const StyledContainer = styled('div')` - grid-column: 1 / span 3; + grid-column: 1 / -1; display: flex; align-items: center; position: sticky; diff --git a/webapp/src/views/projects/dashboard/ActivityGroupsList.tsx b/webapp/src/views/projects/dashboard/ActivityGroupsList.tsx new file mode 100644 index 00000000000..ce8d3eae7a2 --- /dev/null +++ b/webapp/src/views/projects/dashboard/ActivityGroupsList.tsx @@ -0,0 +1,101 @@ +import React, { useEffect, useMemo } from 'react'; +import { styled, Typography, Box } from '@mui/material'; +import { T } from '@tolgee/react'; +import { UseInfiniteQueryResult } from 'react-query'; +import { useInView } from 'react-intersection-observer'; + +import { components } from 'tg.service/apiSchema.generated'; +import { ActivityGroupItem } from 'tg.component/activity/groups/ActivityGroupItem'; +import { ActivityDateSeparator } from 'tg.views/projects/dashboard/ActivityDateSeparator'; +import { useDateCounter } from 'tg.hooks/useDateCounter'; +import { BoxLoading } from 'tg.component/common/BoxLoading'; + +type ActivityGroupModel = components['schemas']['ActivityGroupModel']; +type PagedModelActivityGroupModel = + components['schemas']['PagedModelActivityGroupModel']; + +const StyledContainer = styled('div')` + display: grid; + gap: 5px; + border: 1px solid ${({ theme }) => theme.palette.divider1}; + border-radius: 10px; +`; + +const StyledHeader = styled('div')` + display: flex; + justify-content: space-between; + margin: 12px 18px 8px 12px; +`; + +const StyledScroller = styled('div')` + overflow-y: auto; + overflow-x: hidden; + max-height: 600px; +`; + +const StyledList = styled('div')` + display: grid; + gap: 8px; + padding: 0px 8px 12px 8px; +`; + +const StyledLoadingWrapper = styled(Box)` + justify-self: center; + margin-top: 5px; +`; + +type Props = { + activityLoadable: UseInfiniteQueryResult; +}; + +export const ActivityGroupsList: React.FC = ({ activityLoadable }) => { + const { ref, inView } = useInView({ rootMargin: '100px' }); + + const data = useMemo(() => { + const result: ActivityGroupModel[] = []; + activityLoadable.data?.pages.forEach((p) => + p._embedded?.groups?.forEach((group) => { + result.push(group); + }) + ); + return result; + }, [activityLoadable.data]); + + const counter = useDateCounter(); + + useEffect(() => { + if (inView) { + activityLoadable.fetchNextPage(); + } + }, [inView]); + + return ( + + + + + + + + + {data.map((item) => { + const date = new Date(item.timestamp); + return ( + + {counter.isNewDate(date) && ( + + )} + + + ); + })} + {activityLoadable.hasNextPage && ( + + + + )} + + + + ); +}; diff --git a/webapp/src/views/projects/dashboard/ActivityList.tsx b/webapp/src/views/projects/dashboard/ActivityList.tsx deleted file mode 100644 index d6822ee06e1..00000000000 --- a/webapp/src/views/projects/dashboard/ActivityList.tsx +++ /dev/null @@ -1,151 +0,0 @@ -import React, { useEffect, useMemo } from 'react'; -import { - styled, - Typography, - FormControlLabel, - Switch, - Box, -} from '@mui/material'; -import { T, useTranslate } from '@tolgee/react'; -import { UseInfiniteQueryResult } from 'react-query'; -import { useInView } from 'react-intersection-observer'; - -import { ActivityCompact } from 'tg.component/activity/ActivityCompact/ActivityCompact'; -import { components } from 'tg.service/apiSchema.generated'; -import { ActivityDateSeparator } from 'tg.views/projects/dashboard/ActivityDateSeparator'; -import { useState } from 'react'; -import { useDateCounter } from 'tg.hooks/useDateCounter'; -import { BoxLoading } from 'tg.component/common/BoxLoading'; -import { ActivityDetailDialog } from 'tg.component/activity/ActivityDetail/ActivityDetailDialog'; -import { ActivityModel } from 'tg.component/activity/types'; -import { useUrlSearchState } from 'tg.hooks/useUrlSearchState'; - -type ProjectActivityModel = components['schemas']['ProjectActivityModel']; -type PagedModelProjectActivityModel = - components['schemas']['PagedModelProjectActivityModel']; - -const StyledContainer = styled('div')` - display: grid; - gap: 5px; - border: 1px solid ${({ theme }) => theme.palette.divider1}; - border-radius: 10px; -`; - -const StyledHeader = styled('div')` - display: flex; - justify-content: space-between; - margin: 12px 18px 8px 12px; -`; - -const StyledScroller = styled('div')` - overflow-y: auto; - overflow-x: hidden; - max-height: 600px; -`; - -const StyledList = styled('div')` - display: grid; - grid-template-columns: fit-content(30%) 1fr auto; - gap: 3px 0px; - padding-bottom: 12px; -`; - -const StyledLoadingWrapper = styled(Box)` - grid-column: 1 / span 3; - justify-self: center; - margin-top: 5px; -`; - -type Props = { - activityLoadable: UseInfiniteQueryResult; -}; - -export const ActivityList: React.FC> = ({ - activityLoadable, -}) => { - const { ref, inView } = useInView({ rootMargin: '100px' }); - const [detailData, setDetailData] = useState(); - const [detailId, setDetailId] = useUrlSearchState('activity'); - - const data = useMemo(() => { - const result: ProjectActivityModel[] = []; - activityLoadable.data?.pages.forEach((p) => - p._embedded?.activities?.forEach((activity) => { - result.push(activity); - }) - ); - return result; - }, [activityLoadable.data]); - - const { t } = useTranslate(); - const [diffEnabled, setDiffEnabled] = useState(true); - - const toggleDiff = () => { - setDiffEnabled(!diffEnabled); - }; - - const counter = useDateCounter(); - - useEffect(() => { - if (inView) { - activityLoadable.fetchNextPage(); - } - }, [inView]); - - return ( - - - - - - - } - label={t('dashboard_activity_differences')} - labelPlacement="start" - /> - - - - {data?.map((item) => { - const date = new Date(item.timestamp); - return ( - - {counter.isNewDate(date) && ( - - )} - { - setDetailData(detailData); - setDetailId(String(detailData.revisionId)); - }} - /> - - ); - })} - {activityLoadable.hasNextPage && ( - - - - )} - - - {detailId && ( - { - setDetailData(undefined); - setDetailId(undefined); - }} - maxWidth="lg" - /> - )} - - ); -}; diff --git a/webapp/src/views/projects/dashboard/DashboardView.tsx b/webapp/src/views/projects/dashboard/DashboardView.tsx index 269363cb87c..91a147e84ff 100644 --- a/webapp/src/views/projects/dashboard/DashboardView.tsx +++ b/webapp/src/views/projects/dashboard/DashboardView.tsx @@ -11,7 +11,7 @@ import { useProjectPermissions } from 'tg.hooks/useProjectPermissions'; import { ProjectTotals } from './ProjectTotals'; import { LanguageStats } from './LanguageStats/LanguageStats'; import { DailyActivityChart } from './DailyActivityChart'; -import { ActivityList } from './ActivityList'; +import { ActivityGroupsList } from './ActivityGroupsList'; import { BaseProjectView } from '../BaseProjectView'; import { ProjectDescription } from './ProjectDescription'; import { useReportEvent } from 'tg.hooks/useReportEvent'; @@ -72,7 +72,7 @@ export const DashboardView = () => { const path = { projectId: project.id }; const query = { size: 15, sort: ['timestamp,desc'], branch }; const activityLoadable = useApiInfiniteQuery({ - url: '/v2/projects/{projectId}/activity', + url: '/v2/projects/{projectId}/activity/groups', method: 'get', path, query, @@ -159,7 +159,7 @@ export const DashboardView = () => { gridArea="activityList" data-cy="project-dashboard-activity-list" > - + Date: Sat, 11 Jul 2026 20:10:40 +0200 Subject: [PATCH 52/57] fix: drop explicit buffer import in avatar generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Buffer comes from the global polyfill on main; importing the 'buffer' package (not a direct dependency) broke avatar rendering in production builds — every avatar crashed into the global error dialog, which covered the page and failed the project-list E2E specs. --- webapp/src/component/common/avatar/useAutoAvatarImgSrc.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/webapp/src/component/common/avatar/useAutoAvatarImgSrc.tsx b/webapp/src/component/common/avatar/useAutoAvatarImgSrc.tsx index c4e6be98a55..b43e4c8b427 100644 --- a/webapp/src/component/common/avatar/useAutoAvatarImgSrc.tsx +++ b/webapp/src/component/common/avatar/useAutoAvatarImgSrc.tsx @@ -1,6 +1,5 @@ import { useEffect, useState } from 'react'; import { AutoAvatarProps } from './AutoAvatar'; -import { Buffer } from 'buffer'; function getInitialsAvatarSvg(ownerName: string, size: number, light: boolean) { return Promise.all([ From 10fff7adc33eb9e7293d1dfd740aee8ced98280b Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Mon, 13 Jul 2026 14:44:33 +0200 Subject: [PATCH 53/57] fix: revert branch-era lazy permission languages to main's eager fetch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The branch made Permission.viewLanguages/translateLanguages/stateChangeLanguages lazy with a query-side id prefetch. Assemblers outside the fetching query hit LazyInitializationException, so listing projects with stats 500'd — the global error dialog then covered the page and broke the project-list E2E specs. --- .../io/tolgee/cache/AbstractCacheTest.kt | 4 +- .../main/kotlin/io/tolgee/model/Permission.kt | 71 ++----------------- .../tolgee/repository/PermissionRepository.kt | 16 +---- .../tolgee/service/CachedPermissionService.kt | 3 +- .../service/security/PermissionService.kt | 11 ++- 5 files changed, 18 insertions(+), 87 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 9319968aeef..a3f289659ce 100644 --- a/backend/app/src/test/kotlin/io/tolgee/cache/AbstractCacheTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/cache/AbstractCacheTest.kt @@ -121,7 +121,7 @@ abstract class AbstractCacheTest : AbstractSpringTest() { fun `caches permission by project and user`() { val permission = Permission(id = 1) whenever(permissionRepository.findOneByProjectIdAndUserIdAndOrganizationId(1, 1)) - .then { Permission.PermissionWithLanguageIdsWrapper(permission, null, null, null) } + .then { permission } permissionService.find(1, 1) Mockito .verify(permissionRepository, times(1)) @@ -138,7 +138,7 @@ abstract class AbstractCacheTest : AbstractSpringTest() { whenever( permissionRepository .findOneByProjectIdAndUserIdAndOrganizationId(null, null, organizationId = 1), - ).then { Permission.PermissionWithLanguageIdsWrapper(permission, null, null, null) } + ).then { permission } permissionService.find(organizationId = 1) Mockito 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 abaef6fb175..9beea37a0fb 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/Permission.kt @@ -24,8 +24,6 @@ import jakarta.persistence.OneToOne import jakarta.persistence.PrePersist import jakarta.persistence.PreUpdate import jakarta.persistence.Table -import jakarta.persistence.Transient -import org.hibernate.Hibernate import org.hibernate.annotations.Parameter import org.hibernate.annotations.Type import org.springframework.beans.factory.annotation.Configurable @@ -95,7 +93,7 @@ class Permission( * Languages for TRANSLATIONS_EDIT scope. * When specified, user is restricted to edit specific language translations. */ - @ManyToMany(fetch = FetchType.LAZY) + @ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "permission_languages", inverseJoinColumns = [JoinColumn(name = "languages_id")]) var translateLanguages: MutableSet = mutableSetOf() @@ -110,14 +108,14 @@ class Permission( * Languages for TRANSLATIONS_VIEW scope. * When specified, user is restricted to view specific language translations. */ - @ManyToMany(fetch = FetchType.LAZY) + @ManyToMany(fetch = FetchType.EAGER) var viewLanguages: MutableSet = mutableSetOf() /** * Languages for TRANSLATIONS_STATE_EDIT scope. * When specified, user is restricted to change state only to specific language translations. */ - @ManyToMany(fetch = FetchType.LAZY) + @ManyToMany(fetch = FetchType.EAGER) var stateChangeLanguages: MutableSet = mutableSetOf() constructor( @@ -154,42 +152,14 @@ class Permission( get() = this.project?.id override val organizationId: Long? get() = this.organization?.id - - @Transient - private var fetchedViewLanguageIds: Set? = null - - @Transient - private var fetchedTranslateLanguageIds: 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() - } + get() = this.translateLanguages.map { it.id }.toSet() - return fetchedTranslateLanguageIds - } + override val viewLanguageIds: Set? + get() = this.viewLanguages.map { it.id }.toSet() override val stateChangeLanguageIds: Set? - get() { - if (fetchedStateChangeLanguageIds == null || Hibernate.isInitialized(this.stateChangeLanguages)) { - return this.stateChangeLanguages.map { it.id }.toSet() - } - - return fetchedStateChangeLanguageIds - } + get() = this.stateChangeLanguages.map { it.id }.toSet() override val suggestLanguageIds: Set? get() = this.suggestLanguages.map { it.id }.toSet() @@ -218,31 +188,4 @@ class Permission( } } } - - class PermissionWithLanguageIdsWrapper( - val permission: Permission, - fetchedViewLanguageIds: Any?, - fetchedTranslateLanguageIds: Any?, - fetchedStateChangeLanguageIds: Any?, - ) { - init { - permission.fetchedViewLanguageIds = (fetchedViewLanguageIds as? String) - ?.split(',') - ?.map { e -> e.toLong() } - ?.toSet() - ?: emptySet() - - permission.fetchedTranslateLanguageIds = (fetchedTranslateLanguageIds as? String) - ?.split(',') - ?.map { e -> e.toLong() } - ?.toSet() - ?: emptySet() - - permission.fetchedStateChangeLanguageIds = (fetchedStateChangeLanguageIds as? String) - ?.split(',') - ?.map { e -> e.toLong() } - ?.toSet() - ?: emptySet() - } - } } 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 b0c573ed303..4a7c725540e 100644 --- a/backend/data/src/main/kotlin/io/tolgee/repository/PermissionRepository.kt +++ b/backend/data/src/main/kotlin/io/tolgee/repository/PermissionRepository.kt @@ -12,28 +12,18 @@ import org.springframework.stereotype.Repository interface PermissionRepository : JpaRepository { @Query( """ - SELECT DISTINCT new io.tolgee.model.Permission${'$'}PermissionWithLanguageIdsWrapper( - p, - listagg(str(vl.id), ','), - listagg(str(tl.id), ','), - listagg(str(sl.id), ',') - ) - FROM Permission p - LEFT JOIN p.viewLanguages vl - LEFT JOIN p.translateLanguages tl - LEFT JOIN p.stateChangeLanguages sl - WHERE + from Permission p + 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) - GROUP BY p """, ) fun findOneByProjectIdAndUserIdAndOrganizationId( projectId: Long?, userId: Long?, organizationId: Long? = null, - ): Permission.PermissionWithLanguageIdsWrapper? + ): Permission? fun getAllByProjectAndUserNotNull(project: io.tolgee.model.Project?): Set 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 7063cb72367..adc52dd5867 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/CachedPermissionService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/CachedPermissionService.kt @@ -52,8 +52,7 @@ class CachedPermissionService( projectId = projectId, userId = userId, organizationId = organizationId, - )?.permission - ?.let { permission -> + )?.let { permission -> PermissionDto( id = permission.id, userId = permission.user?.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 529bd288119..263cbe64f63 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 @@ -68,12 +68,11 @@ class PermissionService( userId: Long? = null, organizationId: Long? = null, ): Permission? { - return permissionRepository - .findOneByProjectIdAndUserIdAndOrganizationId( - projectId = projectId, - userId = userId, - organizationId = organizationId, - )?.permission + return permissionRepository.findOneByProjectIdAndUserIdAndOrganizationId( + projectId = projectId, + userId = userId, + organizationId = organizationId, + ) } @Transactional(readOnly = true) From 82453b71654263faaaf0d7c66e9f79cbf3adaff7 Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Mon, 13 Jul 2026 14:44:43 +0200 Subject: [PATCH 54/57] fix: correct SQL generated by activity group value matchers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Value matchers built conditions against the whole modifications json instead of the matched property, and compared json = json which postgres has no operator for. Any group type with allowed/denied values (REVIEW, SET_TRANSLATION_STATE, batch clear...) made the whole groups listing fail with a bad-grammar error. Match on the property attribute, compare as jsonb, and treat JSON null as null. Also match soft-deleted languages in DELETE_LANGUAGE — the hard delete happens asynchronously later. --- .../io/tolgee/activity/groups/ActivityGroupType.kt | 3 ++- .../activity/groups/matchers/EqualsValueMatcher.kt | 7 ++++++- .../activity/groups/matchers/NotNullValueMatcher.kt | 3 ++- .../matchers/modifiedEntity/DefaultMatcher.kt | 13 +++++++------ 4 files changed, 17 insertions(+), 9 deletions(-) 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 df6e84a197c..76a92fb6842 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 @@ -276,7 +276,8 @@ enum class ActivityGroupType( matcher = DefaultMatcher( entityClass = Language::class, - revisionTypes = listOf(RevisionType.DEL), + // language deletion is a soft delete followed by an async hard delete + revisionTypes = listOf(RevisionType.DEL, RevisionType.MOD), ), ), 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 index 5ce8565d784..771128c889e 100644 --- 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 @@ -18,7 +18,12 @@ class EqualsValueMatcher( } override fun createChildSqlCondition(field: Field): Condition { - return field.eq(jsonValue) + // json has no equality operator in postgres, so compare as jsonb; + // an absent attribute yields SQL NULL, an attribute set to null yields JSON null + if (value == null) { + return DSL.condition("({0} is null or {0}::jsonb = 'null'::jsonb)", field) + } + return DSL.condition("{0}::jsonb = {1}::jsonb", field, DSL.`val`(jsonValue)) } override fun createRootSqlCondition(field: Field): Condition { 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 index a49900fbf3b..ceb55a38338 100644 --- 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 @@ -15,7 +15,8 @@ class NotNullValueMatcher : ActivityGroupValueMatcher { } override fun createChildSqlCondition(field: Field): Condition { - return field.isNotNull + // an attribute set to null is JSON null, not SQL NULL + return DSL.condition("({0} is not null and {0}::jsonb <> 'null'::jsonb)", field) } override fun createRootSqlCondition(field: Field): Condition { 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 674344de276..62208d62b18 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 @@ -106,28 +106,29 @@ class DefaultMatcher( } private fun getAllowedValuesCondition(context: SqlContext): Condition { - val allowedValues = allowedValues ?: return DSL.noCondition() + val allowedValues = this.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 deniedValues = this.deniedValues ?: return DSL.noCondition() val conditions = getValueMatcherConditions(context, deniedValues) return DSL.not(DSL.or(conditions)) } private fun getValueMatcherConditions( context: SqlContext, - values: Map, + values: Map, Any?>, ): List { - return values.map { + return values.map { (property, requiredValue) -> val matcher = - when (val requiredValue = it.value) { + when (requiredValue) { is ActivityGroupValueMatcher -> requiredValue else -> EqualsValueMatcher(requiredValue) } - matcher.createRootSqlCondition(context.modificationsField) + val propertyField = DSL.jsonGetAttribute(context.modificationsField, property.name) + matcher.createRootSqlCondition(propertyField) } } } From 1b6b2841f35e7648ee4eedd77f7ef0f3b9e2391e Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Mon, 13 Jul 2026 14:44:58 +0200 Subject: [PATCH 55/57] feat: show trigger origin and compound source actions in activity groups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Record how the request was authenticated (UI / project API key / PAT) on each activity revision and aggregate the distinct origins and source activity types per group. The feed now shows an origin chip on groups touched over the API and attributes groups that emerged from a compound action — e.g. translations set while creating a key render as 'Set translations ... as part of: Created key'. Redesign the group cards along the way: semantic type icon (green for creating, red for deleting), avatar, translated label, count chip, relative time with an exact-datetime tooltip. --- .../hateoas/activity/ActivityGroupModel.kt | 4 + .../activity/ActivityGroupModelAssembler.kt | 10 + .../io/tolgee/activity/data/ActivityOrigin.kt | 10 + .../activity/groups/ActivityGroupsProvider.kt | 7 + .../iterceptor/ActivityRevisionInitializer.kt | 16 + .../dtos/queryResults/ActivityGroupView.kt | 2 + .../tolgee/model/activity/ActivityRevision.kt | 9 + .../main/resources/db/changelog/schema.xml | 5 + e2e/cypress/support/dataCyType.d.ts | 2 + .../activity/groups/ActivityGroupCard.tsx | 213 +- .../activity/groups/groupTypeVisuals.tsx | 91 + webapp/src/i18n/en.json | 5 + webapp/src/service/apiSchema.generated.ts | 16016 ++++++++++++++++ 13 files changed, 16360 insertions(+), 30 deletions(-) create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/data/ActivityOrigin.kt create mode 100644 webapp/src/component/activity/groups/groupTypeVisuals.tsx 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 ea1ceaaea6c..fff0e154348 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 @@ -1,5 +1,7 @@ package io.tolgee.hateoas.activity +import io.tolgee.activity.data.ActivityOrigin +import io.tolgee.activity.data.ActivityType import io.tolgee.activity.groups.ActivityGroupType import io.tolgee.hateoas.userAccount.SimpleUserAccountModel import org.springframework.hateoas.RepresentationModel @@ -15,5 +17,7 @@ class ActivityGroupModel( val author: SimpleUserAccountModel?, val data: Any?, var mentionedLanguageIds: List, + val sourceActivityTypes: List, + val origins: 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 d5da300c7b6..0ea04eb4640 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,5 +1,7 @@ package io.tolgee.hateoas.activity +import io.tolgee.activity.data.ActivityOrigin +import io.tolgee.activity.data.ActivityType import io.tolgee.dtos.queryResults.ActivityGroupView import io.tolgee.hateoas.userAccount.SimpleUserAccountModelAssembler import org.springframework.hateoas.server.RepresentationModelAssembler @@ -20,6 +22,14 @@ class ActivityGroupModelAssembler( ), data = view.data, mentionedLanguageIds = view.mentionedLanguageIds, + sourceActivityTypes = + view.sourceActivityTypes.mapNotNull { type -> + ActivityType.entries.find { it.name == type } + }, + origins = + view.origins.mapNotNull { origin -> + ActivityOrigin.entries.find { it.name == origin } + }, ) } } diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/data/ActivityOrigin.kt b/backend/data/src/main/kotlin/io/tolgee/activity/data/ActivityOrigin.kt new file mode 100644 index 00000000000..6719ae818cd --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/data/ActivityOrigin.kt @@ -0,0 +1,10 @@ +package io.tolgee.activity.data + +/** + * How the request producing the activity was authenticated. + */ +enum class ActivityOrigin { + UI, + API_KEY, + PAT, +} 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 a658e00beea..c09761392e7 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 @@ -56,6 +56,8 @@ class ActivityGroupsProvider( val lmeJsonArrayAggField = jsonArrayAgg(field("lme.entity_id")).`as`("lme_entity_ids") val ldeJsonArrayAggField = jsonArrayAgg(field("lde.entity_id")).`as`("lde_entity_ids") + val sourceTypesAggField = DSL.field("json_agg(distinct ar.type)", String::class.java).`as`("source_types") + val originsAggField = DSL.field("json_agg(distinct ar.origin_type)", String::class.java).`as`("origin_types") if (filters.filterType != null) { where = where.and(field("ag.type").eq(filters.filterType!!.name)) @@ -91,6 +93,8 @@ class ActivityGroupsProvider( field("ua.deleted_at").isNotNull, lmeJsonArrayAggField, ldeJsonArrayAggField, + sourceTypesAggField, + originsAggField, ).from(from) .leftJoin(table("activity_revision_activity_groups").`as`("arag")) .on(field("ag.id").eq(field("arag.activity_groups_id"))) @@ -129,6 +133,9 @@ class ActivityGroupsProvider( override val deleted: Boolean = it[8] as Boolean }, mentionedLanguageIds = parseMentionedLanguageIds(it), + sourceActivityTypes = + it.getJsonValue>("source_types")?.filterNotNull() ?: emptyList(), + origins = it.getJsonValue>("origin_types")?.filterNotNull() ?: emptyList(), ) } diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/iterceptor/ActivityRevisionInitializer.kt b/backend/data/src/main/kotlin/io/tolgee/activity/iterceptor/ActivityRevisionInitializer.kt index 768e7817906..e9d67fa35db 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/iterceptor/ActivityRevisionInitializer.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/iterceptor/ActivityRevisionInitializer.kt @@ -1,6 +1,7 @@ package io.tolgee.activity.iterceptor import io.tolgee.activity.ActivityHolder +import io.tolgee.activity.data.ActivityOrigin import io.tolgee.dtos.cacheable.ProjectDto import io.tolgee.dtos.cacheable.UserAccountDto import io.tolgee.model.activity.ActivityRevision @@ -29,8 +30,23 @@ class ActivityRevisionInitializer( revision.organizationId = organizationId ?: revision.organizationId project?.let { revision.setProject(it) } revision.type = activityHolder.activity ?: revision.type + revision.originType = origin ?: revision.originType } + private val origin: ActivityOrigin? + get() { + if (authenticationFacade.authenticatedUserOrNull == null) { + return null + } + if (authenticationFacade.isProjectApiKeyAuth) { + return ActivityOrigin.API_KEY + } + if (authenticationFacade.isPersonalAccessTokenAuth) { + return ActivityOrigin.PAT + } + return ActivityOrigin.UI + } + /** * Lazily retrieves a project from ProjectHolder. * Returns null if a project is not selected 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 81a5b8b7d33..24e990cf263 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 @@ -10,4 +10,6 @@ data class ActivityGroupView( var data: Any? = null, var author: SimpleUserAccount, var mentionedLanguageIds: List, + var sourceActivityTypes: List = emptyList(), + var origins: List = emptyList(), ) 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 bac2e744c41..1ed7ad9db89 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 @@ -1,6 +1,7 @@ package io.tolgee.model.activity import io.hypersistence.utils.hibernate.type.json.JsonBinaryType +import io.tolgee.activity.data.ActivityOrigin import io.tolgee.activity.data.ActivityType import io.tolgee.api.ProjectIdAndBaseLanguageId import io.tolgee.component.CurrentDateProvider @@ -72,6 +73,14 @@ class ActivityRevision : java.io.Serializable { @Enumerated(EnumType.STRING) var type: ActivityType? = null + /** + * How the request producing this revision was authenticated (null for + * system-triggered activity, e.g. batch chunk processing). + */ + @Enumerated(EnumType.STRING) + @Column(name = "origin_type") + var originType: ActivityOrigin? = null + /** * Project of the change */ diff --git a/backend/data/src/main/resources/db/changelog/schema.xml b/backend/data/src/main/resources/db/changelog/schema.xml index 0fa5a4dfd86..fa13f45fcc5 100644 --- a/backend/data/src/main/resources/db/changelog/schema.xml +++ b/backend/data/src/main/resources/db/changelog/schema.xml @@ -5826,4 +5826,9 @@
+ + + + + diff --git a/e2e/cypress/support/dataCyType.d.ts b/e2e/cypress/support/dataCyType.d.ts index 5ec9fa6bb20..cac2780bde6 100644 --- a/e2e/cypress/support/dataCyType.d.ts +++ b/e2e/cypress/support/dataCyType.d.ts @@ -25,6 +25,8 @@ declare namespace DataCy { "activity-group-expand-button": true; "activity-group-generic-item": true; "activity-group-item": true; + "activity-group-origin": true; + "activity-group-source-info": true; "activity-groups-list": true; "administration-access-message": true; "administration-debug-customer-account-message": true; diff --git a/webapp/src/component/activity/groups/ActivityGroupCard.tsx b/webapp/src/component/activity/groups/ActivityGroupCard.tsx index c4afa4daf0a..83000a46aac 100644 --- a/webapp/src/component/activity/groups/ActivityGroupCard.tsx +++ b/webapp/src/component/activity/groups/ActivityGroupCard.tsx @@ -1,25 +1,57 @@ import React, { FC, PropsWithChildren, useState } from 'react'; -import { Box, Chip, IconButton, styled } from '@mui/material'; -import { ChevronDown, ChevronUp } from '@untitled-ui/icons-react'; +import { Box, Chip, IconButton, styled, Tooltip } from '@mui/material'; +import { ChevronDown, Code02, Terminal } from '@untitled-ui/icons-react'; +import { T } from '@tolgee/react'; import { components } from 'tg.service/apiSchema.generated'; import { AvatarImg } from 'tg.component/common/avatar/AvatarImg'; -import { useDateFormatter } from 'tg.hooks/useLocale'; +import { FormatedDateTooltip } from 'tg.component/common/tooltip/FormatedDateTooltip'; +import { actionsConfiguration } from 'tg.component/activity/configuration'; +import { ActionType } from 'tg.component/activity/types'; +import { getGroupIcon, getGroupSemantic } from './groupTypeVisuals'; type ActivityGroupModel = components['schemas']['ActivityGroupModel']; const StyledContainer = styled('div')` display: grid; - gap: 8px 12px; - padding: 12px 16px; + gap: 2px 12px; + padding: 10px 14px; border-radius: 12px; background: ${({ theme }) => theme.palette.background.paper}; - border: 1px solid ${({ theme }) => theme.palette.divider}; - grid-template-columns: auto 1fr auto auto; + border: 1px solid ${({ theme }) => theme.palette.divider1}; + grid-template-columns: auto auto 1fr auto auto; grid-template-areas: - 'avatar content time expand' - 'expanded expanded expanded expanded'; + 'icon avatar content time expand' + 'expanded expanded expanded expanded expanded'; align-items: center; + transition: background 0.1s ease-out; + + &:hover { + background: ${({ theme }) => theme.palette.cell.hover}; + } +`; + +const StyledIconChip = styled(Box)<{ semantic: string }>` + grid-area: icon; + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + border-radius: 50%; + flex-shrink: 0; + color: ${({ theme, semantic }) => + semantic === 'create' + ? theme.palette.success.main + : semantic === 'delete' + ? theme.palette.error.main + : theme.palette.text.secondary}; + background: ${({ theme }) => theme.palette.tokens.background.hover}; + + & svg { + width: 18px; + height: 18px; + } `; const StyledContent = styled(Box)` @@ -27,17 +59,26 @@ const StyledContent = styled(Box)` display: flex; align-items: center; flex-wrap: wrap; - gap: 4px 8px; + gap: 2px 8px; min-width: 0; `; -const StyledAuthor = styled(Box)` - font-weight: 500; +const StyledAuthor = styled('span')` + font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; `; +const StyledLabel = styled('span')` + min-width: 0; +`; + +const StyledSourceInfo = styled('span')` + color: ${({ theme }) => theme.palette.text.secondary}; + font-size: 13px; +`; + const StyledTime = styled(Box)` grid-area: time; font-size: 12px; @@ -45,9 +86,29 @@ const StyledTime = styled(Box)` white-space: nowrap; `; +const StyledExpandButton = styled(IconButton)<{ expanded?: string }>` + grid-area: expand; + + & svg { + transition: transform 0.2s ease-in-out; + transform: rotate(${({ expanded }) => (expanded ? '180deg' : '0deg')}); + } +`; + const StyledExpanded = styled(Box)` grid-area: expanded; overflow-x: auto; + padding-top: 8px; +`; + +const StyledOriginChip = styled(Chip)` + height: 20px; + font-size: 11px; + + & .MuiChip-icon { + width: 12px; + height: 12px; + } `; type Props = PropsWithChildren<{ @@ -58,19 +119,23 @@ type Props = PropsWithChildren<{ export const ActivityGroupCard: FC = (props) => { const [expanded, setExpanded] = useState(false); - const formatDate = useDateFormatter(); const author = props.item.author; + const Icon = getGroupIcon(props.item.type); + const semantic = getGroupSemantic(props.item.type); return ( + + + {author && ( = (props) => { {author?.name || author?.username} - {props.children} + {props.children} {props.count !== undefined && props.count > 0 && ( = (props) => { data-cy="activity-group-count" /> )} + + - {formatDate(new Date(props.item.timestamp), { - dateStyle: 'medium', - timeStyle: 'short', - })} + - - {props.expandedContent !== undefined && ( - setExpanded(!expanded)} - > - {expanded ? : } - - )} - + {props.expandedContent !== undefined && ( + setExpanded(!expanded)} + > + + + )} {expanded && {props.expandedContent}} ); }; + +const OriginChips: FC<{ item: ActivityGroupModel }> = ({ item }) => { + const origins = item.origins || []; + return ( + <> + {origins.includes('API_KEY') && ( + + } + > + } + data-cy="activity-group-origin" + data-cy-origin="API_KEY" + label={ + + } + /> + + )} + {origins.includes('PAT') && ( + + } + > + } + data-cy="activity-group-origin" + data-cy-origin="PAT" + label={ + + } + /> + + )} + + ); +}; + +/** + * When the underlying activity is a compound action (e.g. translations set + * while creating a key), show which action the group emerged from. + */ +const SourceActivityInfo: FC<{ item: ActivityGroupModel }> = ({ item }) => { + const interestingSources = (item.sourceActivityTypes || []).filter( + (type) => + COMPOUND_SOURCE_TYPES.includes(type) && + // don't attribute a group to its own natural action + type !== (item.type as string) + ); + + if (!interestingSources.length) { + return null; + } + + return ( + + {' '} + {interestingSources.map((type, index) => { + const label = actionsConfiguration[type as ActionType]?.label?.({}); + return ( + + {index > 0 && ', '} + {label ?? type} + + ); + })} + + ); +}; + +const COMPOUND_SOURCE_TYPES = ['COMPLEX_EDIT', 'CREATE_KEY', 'IMPORT']; diff --git a/webapp/src/component/activity/groups/groupTypeVisuals.tsx b/webapp/src/component/activity/groups/groupTypeVisuals.tsx new file mode 100644 index 00000000000..043570aa039 --- /dev/null +++ b/webapp/src/component/activity/groups/groupTypeVisuals.tsx @@ -0,0 +1,91 @@ +import React from 'react'; +import { + CheckVerified01, + ClipboardCheck, + Cloud01, + Edit02, + File06, + GitBranch02, + Globe01, + Image01, + Key01, + LayersTwo01, + MessageTextSquare02, + Package, + Plus, + Settings02, + Tag01, + Translate01, + Trash01, + UploadCloud01, + Zap, +} from '@untitled-ui/icons-react'; + +import { components } from 'tg.service/apiSchema.generated'; + +type ActivityGroupTypeEnum = + components['schemas']['ActivityGroupModel']['type']; + +export type GroupSemantic = 'create' | 'delete' | 'neutral'; + +const DOMAIN_ICONS: [string, React.ComponentType][] = [ + ['SCREENSHOT', Image01], + ['COMMENT', MessageTextSquare02], + ['TAG', Tag01], + ['CHARACTER_LIMIT', Key01], + ['KEY', Key01], + ['BASE_TRANSLATION', Translate01], + ['TRANSLATION_MEMORY', LayersTwo01], + ['TRANSLATION_LABEL', Tag01], + ['LABEL', Tag01], + ['REVIEW', CheckVerified01], + ['SUGGESTION', MessageTextSquare02], + ['TRANSLATION', Translate01], + ['LANGUAGE', Globe01], + ['NAMESPACE', Package], + ['PROJECT', Settings02], + ['IMPORT', UploadCloud01], + ['GLOSSARY', File06], + ['TASK', ClipboardCheck], + ['BRANCH', GitBranch02], + ['AI_PROMPT', Zap], + ['QA_ISSUE', CheckVerified01], + ['WEBHOOK', Zap], + ['CONTENT_DELIVERY', Cloud01], + ['CONTENT_STORAGE', Cloud01], + ['OUTDATED', Translate01], + ['AUTO_TRANSLATE', Translate01], +]; + +export function getGroupIcon( + type: ActivityGroupTypeEnum +): React.ComponentType { + const domainIcon = DOMAIN_ICONS.find(([domain]) => + type.includes(domain) + )?.[1]; + if (domainIcon) { + return domainIcon; + } + if (type.startsWith('CREATE') || type.startsWith('ADD')) { + return Plus; + } + if (type.includes('DELETE')) { + return Trash01; + } + return Edit02; +} + +export function getGroupSemantic(type: ActivityGroupTypeEnum): GroupSemantic { + if ( + type.startsWith('CREATE') || + type.startsWith('ADD') || + type.startsWith('IMPORT') || + type === 'RESTORE_KEY' + ) { + return 'create'; + } + if (type.includes('DELETE')) { + return 'delete'; + } + return 'neutral'; +} diff --git a/webapp/src/i18n/en.json b/webapp/src/i18n/en.json index ed7dfaf0f6f..3b02042bdf8 100644 --- a/webapp/src/i18n/en.json +++ b/webapp/src/i18n/en.json @@ -52,6 +52,11 @@ "active-plan-license-key-button": "Show license key", "active-plan-license-key-caption": "Apply this license key in your local Tolgee instance", "active-plan-subscribed-at-tooltip": "Subscribed at", + "activity_groups_origin_api_key": "API key", + "activity_groups_origin_api_key_hint": "Done over the API with a project API key", + "activity_groups_origin_pat": "PAT", + "activity_groups_origin_pat_hint": "Done over the API with a personal access token", + "activity_groups_source_info_prefix": "as part of:", "activity_groups_base_translation_column": "Base translation", "activity_groups_key_name_column": "Key", "activity_groups_type_accept_suggestion": "Accepted suggestions", diff --git a/webapp/src/service/apiSchema.generated.ts b/webapp/src/service/apiSchema.generated.ts index 603e13e4424..6a4a3e36893 100644 --- a/webapp/src/service/apiSchema.generated.ts +++ b/webapp/src/service/apiSchema.generated.ts @@ -1322,6 +1322,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1332,6 +1436,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1342,6 +1550,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1352,6 +1664,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1362,6 +1778,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1372,6 +1892,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1382,6 +2006,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1392,6 +2120,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1402,6 +2234,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1412,6 +2348,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1422,6 +2462,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1432,6 +2576,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1442,6 +2690,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1452,6 +2804,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1462,6 +2918,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1472,6 +3032,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1482,6 +3146,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1492,6 +3260,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1502,6 +3374,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1512,6 +3488,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1522,6 +3602,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1536,6 +3720,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1546,6 +3834,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1563,6 +3955,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1573,6 +4069,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1583,6 +4183,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1593,6 +4297,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1603,6 +4411,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1613,6 +4525,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1623,6 +4639,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1633,6 +4753,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1643,6 +4867,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1653,6 +4981,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1663,6 +5095,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1673,6 +5209,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1683,6 +5323,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1693,6 +5437,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1703,6 +5551,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1713,6 +5665,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1723,6 +5779,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1733,6 +5893,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1743,6 +6007,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1753,6 +6121,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1763,6 +6235,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1773,6 +6349,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1783,6 +6463,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1793,6 +6577,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1803,6 +6691,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1813,6 +6805,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1823,6 +6919,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1833,6 +7033,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1843,6 +7147,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1853,6 +7261,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1863,6 +7375,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1873,6 +7489,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1883,6 +7603,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1893,6 +7717,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1911,6 +7839,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1926,6 +7958,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1936,6 +8072,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1946,6 +8186,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1956,6 +8300,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1966,6 +8414,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1976,6 +8528,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -1990,6 +8646,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2000,6 +8760,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2010,6 +8874,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2020,6 +8988,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2030,6 +9102,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2040,6 +9216,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2050,6 +9330,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2060,6 +9444,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2070,6 +9558,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2080,6 +9672,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2090,6 +9786,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2100,6 +9900,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2110,6 +10014,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2120,6 +10128,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2137,6 +10249,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2147,6 +10363,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2157,6 +10477,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2167,6 +10591,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2177,6 +10705,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2187,6 +10819,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2197,6 +10933,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2207,6 +11047,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2217,6 +11161,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2227,6 +11275,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2237,6 +11389,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2247,6 +11503,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2257,6 +11617,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2267,6 +11731,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2277,6 +11845,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2287,6 +11959,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2297,6 +12073,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2307,6 +12187,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2317,6 +12301,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2327,6 +12415,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2337,6 +12529,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2347,6 +12643,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2357,6 +12757,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2367,6 +12871,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2377,6 +12985,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2387,6 +13099,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2397,6 +13213,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2407,6 +13327,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2417,6 +13441,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2427,6 +13555,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2437,6 +13669,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2447,6 +13783,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2457,6 +13897,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2467,6 +14011,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2477,6 +14125,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2487,6 +14239,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2497,6 +14353,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2507,6 +14467,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2517,6 +14581,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2527,6 +14695,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2537,6 +14809,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2547,6 +14923,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2557,6 +15037,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2567,6 +15151,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2577,6 +15265,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2587,6 +15379,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2597,6 +15493,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2607,6 +15607,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2617,6 +15721,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2627,6 +15835,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2637,6 +15949,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2647,6 +16063,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2657,6 +16177,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2667,6 +16291,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2677,6 +16405,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2687,6 +16519,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2697,6 +16633,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2707,6 +16747,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2717,6 +16861,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2727,6 +16975,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2737,6 +17089,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2747,6 +17203,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2757,6 +17317,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2767,6 +17431,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2777,6 +17545,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2787,6 +17659,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2797,6 +17773,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2807,6 +17887,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2817,6 +18001,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2831,6 +18119,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2841,6 +18233,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2851,6 +18347,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2861,6 +18461,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2871,6 +18575,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2881,6 +18689,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ @@ -2891,6 +18803,110 @@ export interface components { /** Format: int64 */ id: number; mentionedLanguageIds: number[]; + origins: ("UI" | "API_KEY" | "PAT")[]; + sourceActivityTypes: ( + | "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_CHARACTER_LIMIT_EDIT" + | "KEY_DELETE" + | "KEY_SOFT_DELETE" + | "KEY_RESTORE" + | "KEY_HARD_DELETE" + | "BATCH_KEY_RESTORE" + | "BATCH_KEY_HARD_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" + | "BATCH_ASSIGN_TRANSLATION_LABEL" + | "BATCH_UNASSIGN_TRANSLATION_LABEL" + | "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" + | "TASKS_CREATE" + | "TASK_CREATE" + | "TASK_UPDATE" + | "TASK_KEYS_UPDATE" + | "TASK_FINISH" + | "TASK_CLOSE" + | "TASK_REOPEN" + | "TASK_KEY_UPDATE" + | "ORDER_TRANSLATION" + | "GLOSSARY_CREATE" + | "GLOSSARY_UPDATE" + | "GLOSSARY_DELETE" + | "GLOSSARY_IMPORT" + | "GLOSSARY_TERM_CREATE" + | "GLOSSARY_TERM_UPDATE" + | "GLOSSARY_TERM_DELETE" + | "GLOSSARY_TERM_TRANSLATION_UPDATE" + | "TRANSLATION_MEMORY_CREATE" + | "TRANSLATION_MEMORY_UPDATE" + | "TRANSLATION_MEMORY_DELETE" + | "TRANSLATION_MEMORY_ASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UNASSIGN_PROJECT" + | "TRANSLATION_MEMORY_UPDATE_PROJECT_CONFIG" + | "TRANSLATION_MEMORY_ENTRY_CREATE" + | "TRANSLATION_MEMORY_ENTRY_UPDATE" + | "TRANSLATION_MEMORY_ENTRY_DELETE" + | "TRANSLATION_MEMORY_IMPORT" + | "TRANSLATION_MEMORY_COPY_FROM_PROJECT" + | "TRANSLATION_LABELS_EDIT" + | "TRANSLATION_LABEL_ASSIGN" + | "TRANSLATION_LABEL_CREATE" + | "TRANSLATION_LABEL_UPDATE" + | "TRANSLATION_LABEL_DELETE" + | "CREATE_SUGGESTION" + | "DECLINE_SUGGESTION" + | "ACCEPT_SUGGESTION" + | "REVERSE_SUGGESTION" + | "DELETE_SUGGESTION" + | "SUGGESTION_SET_ACTIVE" + | "AI_PROMPT_CREATE" + | "AI_PROMPT_UPDATE" + | "AI_PROMPT_DELETE" + | "BRANCH_CREATE" + | "BRANCH_RENAME" + | "BRANCH_DELETE" + | "BRANCH_PROTECTION_CHANGE" + | "BRANCH_MERGE" + | "QA_ISSUE_IGNORE" + | "QA_ISSUE_UNIGNORE" + )[]; /** Format: int64 */ timestamp: number; /** @enum {string} */ From 8476dc86c9b82c20d22d585e8447460e74540960 Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Mon, 13 Jul 2026 15:13:01 +0200 Subject: [PATCH 56/57] feat: make expanded group items readable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - IMPORT had no matcher, so its expanded list was always empty — match the keys and translations the import created - resolve the describing relations of generic group items, so a translation row shows its key name and language instead of a bare entity id - render modifications as old → new, formatting entity references by name, timestamps as dates and arrays as lists, instead of dumping field names - fall back to the deleted entity's previous name when it no longer has describing data --- .../activity/groups/ActivityGroupType.kt | 11 ++ .../dataProviders/GenericRelationsProvider.kt | 82 +++++++++ .../groups/dataProviders/GroupDataProvider.kt | 10 ++ .../generic/GenericGroupItemModel.kt | 13 +- .../generic/GenericGroupModelProvider.kt | 67 +++++--- .../groups/GenericGroupExpandedContent.tsx | 159 ++++++++++++++++-- webapp/src/i18n/en.json | 3 + webapp/src/service/apiSchema.generated.ts | 17 +- .../src/service/apiSchemaTypes.generated.ts | 2 +- 9 files changed, 318 insertions(+), 46 deletions(-) create mode 100644 backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/GenericRelationsProvider.kt 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 76a92fb6842..7c47798f102 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 @@ -250,6 +250,17 @@ enum class ActivityGroupType( IMPORT( listOf(ActivityType.IMPORT), + matcher = + DefaultMatcher( + entityClass = Key::class, + revisionTypes = listOf(RevisionType.ADD), + ).or( + DefaultMatcher( + entityClass = Translation::class, + revisionTypes = listOf(RevisionType.ADD, RevisionType.MOD), + modificationProps = listOf(Translation::text), + ), + ), ), CREATE_LANGUAGE( diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/GenericRelationsProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/GenericRelationsProvider.kt new file mode 100644 index 00000000000..5097f36788d --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/dataProviders/GenericRelationsProvider.kt @@ -0,0 +1,82 @@ +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.ModifiedEntityView +import org.jooq.DSLContext +import org.jooq.JSON +import org.jooq.impl.DSL + +/** + * Resolves whatever describing relations the given modified entities happen to have, + * without requiring a per-group-type mapping. + */ +class GenericRelationsProvider( + private val jooqContext: DSLContext, + private val objectMapper: ObjectMapper, + private val entities: List, +) { + 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) + + /** + * @return modified entity -> (relation field name -> describing entity) + */ + fun provide(): Map> { + if (refs.isEmpty()) { + return emptyMap() + } + + val views = + jooqContext + .select(entityIdField, entityClassField, dataField, describingRelationsField, activityRevisionIdField) + .from(DSL.table("activity_describing_entity").`as`("ade")) + .where( + DSL.or( + refs.map { (entity, _, ref) -> + entityClassField + .eq(ref.entityClass) + .and(entityIdField.eq(ref.entityId)) + .and(activityRevisionIdField.eq(entity.activityRevisionId)) + }, + ), + ).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), + ) + } + + return refs + .groupBy { it.first } + .mapValues { (_, entityRefs) -> + entityRefs + .mapNotNull { (entity, field, ref) -> + val view = + views.find { + it.entityId == ref.entityId && + it.entityClass == ref.entityClass && + it.activityRevisionId == entity.activityRevisionId + } ?: return@mapNotNull null + field to view + }.toMap() + } + } + + private val refs by lazy { + entities.flatMap { entity -> + entity.describingRelations.mapNotNull { (field, ref) -> + ref ?: return@mapNotNull null + Triple(entity, field, 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 737baab16a0..aa4ae08e8ca 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 @@ -104,6 +104,16 @@ class GroupDataProvider( } } + fun getGenericRelations( + entities: List, + ): Map> { + return GenericRelationsProvider( + jooqContext = jooqContext, + objectMapper = objectMapper, + entities = entities, + ).provide() + } + fun getDescribingEntities( entities: Iterable, describingMapping: List, diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/generic/GenericGroupItemModel.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/generic/GenericGroupItemModel.kt index d7359527ad6..6fcbbfbd789 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/generic/GenericGroupItemModel.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/generic/GenericGroupItemModel.kt @@ -1,12 +1,21 @@ package io.tolgee.activity.groups.viewProviders.generic -import io.tolgee.activity.data.EntityDescriptionRef import io.tolgee.activity.data.PropertyModification data class GenericGroupItemModel( val entityClass: String, val entityId: Long, val description: Map, - val describingRelations: Map, + /** + * Related entities describing this one (e.g. the key and language of a translation), + * keyed by the relation name, with their describing data resolved. + */ + val relations: Map, val modifications: Map, ) + +data class GenericGroupItemRelationModel( + val entityClass: String, + val entityId: Long, + val data: Map, +) diff --git a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/generic/GenericGroupModelProvider.kt b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/generic/GenericGroupModelProvider.kt index afcf267ee13..8d70c7801f5 100644 --- a/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/generic/GenericGroupModelProvider.kt +++ b/backend/data/src/main/kotlin/io/tolgee/activity/groups/viewProviders/generic/GenericGroupModelProvider.kt @@ -1,8 +1,11 @@ package io.tolgee.activity.groups.viewProviders.generic +import com.fasterxml.jackson.databind.ObjectMapper import io.tolgee.activity.groups.ActivityGroupType +import io.tolgee.activity.groups.data.ModifiedEntityView import io.tolgee.activity.groups.dataProviders.CountsProvider import io.tolgee.activity.groups.dataProviders.GroupDataProvider +import io.tolgee.activity.groups.dataProviders.PagedRelevantModifiedEntitiesProvider import org.jooq.DSLContext import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable @@ -10,23 +13,28 @@ import org.springframework.stereotype.Component /** * Group data for group types without a specialized [io.tolgee.activity.groups.GroupModelProvider]: - * per-entity-class counts for the group header and paged raw modified entities for the expanded view. + * per-entity-class counts for the group header and paged modified entities, with their describing + * relations resolved, for the expanded view. */ @Component class GenericGroupModelProvider( private val jooqContext: DSLContext, + private val objectMapper: ObjectMapper, private val groupDataProvider: GroupDataProvider, ) { fun provideCounts( groupType: ActivityGroupType, groupIds: List, ): Map { - val entityClasses = groupType.matcher?.relevantEntityClasses ?: return emptyMap() + val entityClasses = groupType.entityClassNames + if (entityClasses.isEmpty()) { + return emptyMap() + } val counts = CountsProvider( jooqContext = jooqContext, groupType = groupType, - entityClasses = entityClasses.mapNotNull { it.simpleName }, + entityClasses = entityClasses, groupIds = groupIds, ).provide() return counts.mapValues { GenericGroupModel(it.value) } @@ -37,27 +45,46 @@ class GenericGroupModelProvider( groupId: Long, pageable: Pageable, ): Page { - val entityClass = - groupType.matcher?.relevantEntityClasses?.firstOrNull() - ?: return Page.empty(pageable) + val entityClasses = groupType.entityClassNames + if (entityClasses.isEmpty()) { + return Page.empty(pageable) + } - @Suppress("UNCHECKED_CAST") val entities = - groupDataProvider.provideRelevantModifiedEntities( + PagedRelevantModifiedEntitiesProvider( + jooqContext = jooqContext, + objectMapper = objectMapper, groupType = groupType, - entityClass = entityClass as kotlin.reflect.KClass, + entityClasses = entityClasses, groupId = groupId, pageable = pageable, - ) - - return entities.map { - GenericGroupItemModel( - entityClass = it.entityClass, - entityId = it.entityId, - description = it.describingData, - describingRelations = it.describingRelations, - modifications = it.modifications, - ) - } + ).provide() + + val relations = groupDataProvider.getGenericRelations(entities.content) + + return entities.map { entity -> entity.toModel(relations[entity]) } } + + private fun ModifiedEntityView.toModel( + relations: Map?, + ): GenericGroupItemModel { + return GenericGroupItemModel( + entityClass = entityClass, + entityId = entityId, + description = describingData, + relations = + relations + ?.mapValues { (_, view) -> + GenericGroupItemRelationModel( + entityClass = view.entityClass, + entityId = view.entityId, + data = view.data, + ) + }.orEmpty(), + modifications = modifications, + ) + } + + private val ActivityGroupType.entityClassNames: List + get() = matcher?.relevantEntityClasses?.mapNotNull { it.simpleName }.orEmpty() } diff --git a/webapp/src/component/activity/groups/GenericGroupExpandedContent.tsx b/webapp/src/component/activity/groups/GenericGroupExpandedContent.tsx index 03f59d245b6..8711e2ee1b0 100644 --- a/webapp/src/component/activity/groups/GenericGroupExpandedContent.tsx +++ b/webapp/src/component/activity/groups/GenericGroupExpandedContent.tsx @@ -1,11 +1,13 @@ import React, { FC, useState } from 'react'; import { + styled, Table, TableBody, TableCell, TableHead, TableRow, } from '@mui/material'; +import { T } from '@tolgee/react'; import { useApiQuery } from 'tg.service/http/useQueryApi'; import { useProject } from 'tg.hooks/useProject'; @@ -14,7 +16,25 @@ import { components } from 'tg.service/apiSchema.generated'; type GenericGroupItemModel = components['schemas']['GenericGroupItemModel']; -const DISPLAYED_DESCRIPTION_FIELDS = ['name', 'text', 'key', 'tag', 'username']; +const StyledOld = styled('span')` + color: ${({ theme }) => theme.palette.text.secondary}; + text-decoration: line-through; +`; + +const StyledNew = styled('span')` + color: ${({ theme }) => theme.palette.text.primary}; +`; + +const StyledEntity = styled('span')` + color: ${({ theme }) => theme.palette.text.secondary}; +`; + +const StyledLanguage = styled('span')` + color: ${({ theme }) => theme.palette.text.secondary}; +`; + +const MAX_DISPLAYED_MODIFICATIONS = 3; +const MAX_VALUE_LENGTH = 60; export const GenericGroupExpandedContent: FC<{ groupId: number }> = (props) => { const project = useProject(); @@ -34,9 +54,18 @@ export const GenericGroupExpandedContent: FC<{ groupId: number }> = (props) => { listComponent={ItemsTable} renderItem={(item: GenericGroupItemModel) => ( - {item.entityClass} - {describe(item)} - {modificationSummary(item)} + + {item.entityClass} + + + {getTitle(item)} + {getLanguageTag(item) && ( + ({getLanguageTag(item)}) + )} + + + + )} /> @@ -47,26 +76,126 @@ const ItemsTable: FC = (props) => ( - - - + + + + + + + + + {props.children}
); -function describe(item: GenericGroupItemModel): string { - for (const field of DISPLAYED_DESCRIPTION_FIELDS) { - const value = item.description?.[field]; - if (typeof value === 'string' && value) { - return value; +const Modifications: FC<{ item: GenericGroupItemModel }> = ({ item }) => { + const modifications = Object.entries(item.modifications || {}); + const displayed = modifications.slice(0, MAX_DISPLAYED_MODIFICATIONS); + + return ( + <> + {displayed.map(([field, modification], index) => ( + + {index > 0 && ', '} + {field}: + {modification.old !== undefined && modification.old !== null && ( + <> + {formatValue(field, modification.old)} + {' → '} + + )} + {formatValue(field, modification.new)} + + ))} + {modifications.length > displayed.length && + ` +${modifications.length - displayed.length}`} + + ); +}; + +const TITLE_FIELDS = ['name', 'text', 'tag', 'username', 'url']; + +function getTitle(item: GenericGroupItemModel): string { + // a translation is best identified by the key it belongs to + const keyName = item.relations?.key?.data?.name; + if (typeof keyName === 'string' && keyName) { + return keyName; + } + + for (const field of TITLE_FIELDS) { + const described = item.description?.[field]; + if (typeof described === 'string' && described) { + return described; + } + const modification = item.modifications?.[field]; + for (const value of [modification?.new, modification?.old]) { + if (typeof value === 'string' && value) { + return value; + } } } + return `#${item.entityId}`; } -function modificationSummary(item: GenericGroupItemModel): string { - const mods = item.modifications || {}; - return Object.keys(mods).join(', '); +function getLanguageTag(item: GenericGroupItemModel): string | undefined { + const tag = item.relations?.language?.data?.tag; + return typeof tag === 'string' ? tag : undefined; +} + +const NAME_FIELDS = ['name', 'text', 'tag', 'title']; + +function formatValue(field: string, value: unknown): string { + return truncate(stringifyValue(field, value)); +} + +function stringifyValue(field: string, value: unknown): string { + if (value === null || value === undefined) { + return '∅'; + } + + if (typeof value === 'string') { + return value; + } + + if (typeof value === 'number') { + return isTimestampField(field) + ? new Date(value).toLocaleString() + : String(value); + } + + if (Array.isArray(value)) { + return value.map((item) => stringifyValue(field, item)).join(', ') || '∅'; + } + + if (typeof value === 'object') { + // entity references and describing data carry their own name + const reference = value as Record; + const data = reference.data ?? reference; + for (const nameField of NAME_FIELDS) { + const name = data?.[nameField]; + if (typeof name === 'string' && name) { + return name; + } + } + if (reference.entityId) { + return `#${reference.entityId}`; + } + return JSON.stringify(value); + } + + return String(value); +} + +function isTimestampField(field: string): boolean { + return field.endsWith('At') || field.endsWith('Date'); +} + +function truncate(text: string): string { + return text.length > MAX_VALUE_LENGTH + ? `${text.slice(0, MAX_VALUE_LENGTH)}…` + : text; } diff --git a/webapp/src/i18n/en.json b/webapp/src/i18n/en.json index 3b02042bdf8..4d7e7055b60 100644 --- a/webapp/src/i18n/en.json +++ b/webapp/src/i18n/en.json @@ -58,6 +58,9 @@ "activity_groups_origin_pat_hint": "Done over the API with a personal access token", "activity_groups_source_info_prefix": "as part of:", "activity_groups_base_translation_column": "Base translation", + "activity_groups_change_column": "Change", + "activity_groups_entity_column": "Entity", + "activity_groups_item_column": "Item", "activity_groups_key_name_column": "Key", "activity_groups_type_accept_suggestion": "Accepted suggestions", "activity_groups_type_add_screenshot": "Added screenshots", diff --git a/webapp/src/service/apiSchema.generated.ts b/webapp/src/service/apiSchema.generated.ts index 6a4a3e36893..2258d998691 100644 --- a/webapp/src/service/apiSchema.generated.ts +++ b/webapp/src/service/apiSchema.generated.ts @@ -20444,11 +20444,6 @@ export interface components { | "KEY_USED_BY_ANOTHER_INSTANCE" | "UNKNOWN"; }; - EntityDescriptionRef: { - entityClass: string; - /** Format: int64 */ - entityId: number; - }; EntityDescriptionWithRelations: { data: { [key: string]: unknown }; entityClass: string; @@ -20969,9 +20964,6 @@ export interface components { oldSlug?: string; }; GenericGroupItemModel: { - describingRelations: { - [key: string]: components["schemas"]["EntityDescriptionRef"]; - }; description: { [key: string]: unknown }; entityClass: string; /** Format: int64 */ @@ -20979,6 +20971,15 @@ export interface components { modifications: { [key: string]: components["schemas"]["PropertyModification"]; }; + relations: { + [key: string]: components["schemas"]["GenericGroupItemRelationModel"]; + }; + }; + GenericGroupItemRelationModel: { + data: { [key: string]: unknown }; + entityClass: string; + /** Format: int64 */ + entityId: number; }; GetKeysRequestDto: { keys: components["schemas"]["KeyDefinitionDto"][]; diff --git a/webapp/src/service/apiSchemaTypes.generated.ts b/webapp/src/service/apiSchemaTypes.generated.ts index 28d0e397792..f2ad957afec 100644 --- a/webapp/src/service/apiSchemaTypes.generated.ts +++ b/webapp/src/service/apiSchemaTypes.generated.ts @@ -187,7 +187,6 @@ export type DryRunMergeBranchRequest = components['schemas']['DryRunMergeBranchR export type EditKeyDto = components['schemas']['EditKeyDto']; export type EditProjectRequest = components['schemas']['EditProjectRequest']; export type EeSubscriptionModel = components['schemas']['EeSubscriptionModel']; -export type EntityDescriptionRef = components['schemas']['EntityDescriptionRef']; export type EntityDescriptionWithRelations = components['schemas']['EntityDescriptionWithRelations']; export type ErrorResponseBody = components['schemas']['ErrorResponseBody']; export type ErrorResponseTyped = components['schemas']['ErrorResponseTyped']; @@ -196,6 +195,7 @@ export type ExportFormatModel = components['schemas']['ExportFormatModel']; export type ExportParams = components['schemas']['ExportParams']; export type GenerateSlugDto = components['schemas']['GenerateSlugDto']; export type GenericGroupItemModel = components['schemas']['GenericGroupItemModel']; +export type GenericGroupItemRelationModel = components['schemas']['GenericGroupItemRelationModel']; export type GetKeysRequestDto = components['schemas']['GetKeysRequestDto']; export type GlossaryHighlightsRequest = components['schemas']['GlossaryHighlightsRequest']; export type GlossaryImportResult = components['schemas']['GlossaryImportResult']; From ce4b2e6b5ebdf8c701e66182211f7044281d8af1 Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Mon, 13 Jul 2026 15:54:17 +0200 Subject: [PATCH 57/57] test: migrate activity e2e specs to the grouped dashboard The dashboard no longer renders per-revision compact rows, so the specs that asserted them (labels, translation labels, suggestions, outdated) now assert group cards by type and expand them to check the affected items. Drop the unused E2ActivityChecker compound. Also show the entity's own text under the item title, so a suggestion row shows the suggested translation next to the key it belongs to. --- e2e/cypress/common/activities.ts | 36 ++++++++++++------- e2e/cypress/compounds/E2ActivityChecker.ts | 27 -------------- e2e/cypress/e2e/projects/labels.cy.ts | 19 +++++----- .../suggestions/suggestions.reviewer.cy.ts | 28 +++++++-------- e2e/cypress/e2e/translations/outdated.cy.ts | 12 +++++-- .../e2e/translations/translationLabels.cy.ts | 14 ++++---- .../groups/GenericGroupExpandedContent.tsx | 35 ++++++++++++++++-- 7 files changed, 94 insertions(+), 77 deletions(-) delete mode 100644 e2e/cypress/compounds/E2ActivityChecker.ts diff --git a/e2e/cypress/common/activities.ts b/e2e/cypress/common/activities.ts index 6b6baa6b35e..d43d98b1d61 100644 --- a/e2e/cypress/common/activities.ts +++ b/e2e/cypress/common/activities.ts @@ -1,22 +1,32 @@ -import { gcy, selectInProjectMenu } from './shared'; +import { gcyAdvanced, selectInProjectMenu } from './shared'; -export function checkActivity(activityText: string) { - selectInProjectMenu('Project Dashboard'); - cy.waitForDom(); +/** + * Expands the activity group of the given type on the project dashboard. + */ +export function expandActivityGroup(groupType: string) { + gcyAdvanced({ value: 'activity-group-item', type: groupType }) + .should('be.visible') + .findDcy('activity-group-expand-button') + .click(); - gcy('activity-compact').contains(activityText).should('be.visible'); + return cy; +} - gcy('activity-compact') - .contains(activityText) - .closestDcy('activity-compact') - .findDcy('activity-compact-detail-button') - .click({ force: true }); +/** + * Opens the project dashboard and expands the activity group of the given type. + */ +export function checkActivityGroup(groupType: string) { + selectInProjectMenu('Project Dashboard'); + cy.waitForDom(); - return cy; + return expandActivityGroup(groupType); } -export function assertActivityDetails(expectedTexts: string[]) { - gcy('activity-detail-dialog').within(() => { +export function assertActivityGroupDetails( + groupType: string, + expectedTexts: string[] +) { + gcyAdvanced({ value: 'activity-group-item', type: groupType }).within(() => { expectedTexts.forEach((text) => { cy.contains(text).should('be.visible'); }); diff --git a/e2e/cypress/compounds/E2ActivityChecker.ts b/e2e/cypress/compounds/E2ActivityChecker.ts deleted file mode 100644 index af7e3945da5..00000000000 --- a/e2e/cypress/compounds/E2ActivityChecker.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { gcy, selectInProjectMenu } from '../common/shared'; - -export class E2ActivityChecker { - checkActivity(activityText: string) { - selectInProjectMenu('Project Dashboard'); - cy.waitForDom(); - - gcy('activity-compact').contains(activityText).should('be.visible'); - - gcy('activity-compact') - .contains(activityText) - .closestDcy('activity-compact') - .findDcy('activity-compact-detail-button') - .click({ force: true }); - - return this; - } - - assertActivityDetails(expectedTexts: string[]) { - gcy('activity-detail-dialog').within(() => { - expectedTexts.forEach((text) => { - cy.contains(text).should('be.visible'); - }); - }); - return this; - } -} diff --git a/e2e/cypress/e2e/projects/labels.cy.ts b/e2e/cypress/e2e/projects/labels.cy.ts index 5c4f9b32582..6086a43d247 100644 --- a/e2e/cypress/e2e/projects/labels.cy.ts +++ b/e2e/cypress/e2e/projects/labels.cy.ts @@ -3,7 +3,10 @@ import { labelsTestData } from '../../common/apiCalls/testData/testData'; import { assertMessage, assertMissingFeature, gcy } from '../../common/shared'; import { E2ProjectLabelsSection } from '../../compounds/projectSettings/labels/E2ProjectLabelsSection'; import { isDarkMode } from '../../common/helpers'; -import { assertActivityDetails, checkActivity } from '../../common/activities'; +import { + assertActivityGroupDetails, + checkActivityGroup, +} from '../../common/activities'; import { setFeature } from '../../common/features'; let projectId = null; @@ -97,9 +100,8 @@ describe('Projects Settings - Labels', () => { const labelModal = projectLabels.openCreateLabelModal(); labelModal.fillAndSave('test-label', '#FF0055', 'New label description'); - checkActivity('Created translation label'); - assertActivityDetails([ - 'Created translation label', + checkActivityGroup('CREATE_TRANSLATION_LABEL'); + assertActivityGroupDetails('CREATE_TRANSLATION_LABEL', [ 'test-label', 'New label description', ]); @@ -111,8 +113,8 @@ describe('Projects Settings - Labels', () => { const labelModal = projectLabels.openEditLabelModal('First label'); labelModal.fillAndSave('Edited label', '#00FF00', 'Totally new text'); - checkActivity('Edited translation label'); - assertActivityDetails(['Edited translation label']); + checkActivityGroup('EDIT_TRANSLATION_LABEL'); + assertActivityGroupDetails('EDIT_TRANSLATION_LABEL', ['Edited label']); }); it('creates activity when label is deleted', () => { @@ -120,9 +122,8 @@ describe('Projects Settings - Labels', () => { projectLabels.deleteLabel('First label'); - checkActivity('Deleted translation label'); - assertActivityDetails([ - 'Deleted translation label', + checkActivityGroup('DELETE_TRANSLATION_LABEL'); + assertActivityGroupDetails('DELETE_TRANSLATION_LABEL', [ 'This is a description', ]); }); diff --git a/e2e/cypress/e2e/projects/suggestions/suggestions.reviewer.cy.ts b/e2e/cypress/e2e/projects/suggestions/suggestions.reviewer.cy.ts index bbda50be919..d7634445562 100644 --- a/e2e/cypress/e2e/projects/suggestions/suggestions.reviewer.cy.ts +++ b/e2e/cypress/e2e/projects/suggestions/suggestions.reviewer.cy.ts @@ -1,3 +1,7 @@ +import { + assertActivityGroupDetails, + expandActivityGroup, +} from '../../../common/activities'; import { login } from '../../../common/apiCalls/common'; import { suggestionsTestData } from '../../../common/apiCalls/testData/testData'; import { waitForGlobalLoading } from '../../../common/loading'; @@ -99,10 +103,8 @@ describe('Suggestions reviewer', () => { .findDcy('translation-suggestion') .should('have.length', 1); visitProjectDashboard(projectId); - gcyAdvanced({ - value: 'activity-compact', - type: 'SUGGESTION_SET_ACTIVE', - }).should('contain', 'Navržený překlad'); + expandActivityGroup('SET_SUGGESTION_ACTIVE'); + assertActivityGroupDetails('SET_SUGGESTION_ACTIVE', ['Navržený překlad']); }); it('reviewer can decline suggestion', () => { @@ -120,10 +122,8 @@ describe('Suggestions reviewer', () => { .should('have.length', 1); visitProjectDashboard(projectId); - gcyAdvanced({ - value: 'activity-compact', - type: 'DECLINE_SUGGESTION', - }).should('contain', 'Navržený překlad'); + expandActivityGroup('DECLINE_SUGGESTION'); + assertActivityGroupDetails('DECLINE_SUGGESTION', ['Navržený překlad']); }); it('reviewer can delete his own suggestion', () => { @@ -141,10 +141,8 @@ describe('Suggestions reviewer', () => { .should('not.exist'); visitProjectDashboard(projectId); - gcyAdvanced({ - value: 'activity-compact', - type: 'DELETE_SUGGESTION', - }).should('contain', 'Navržený překlad'); + expandActivityGroup('DELETE_SUGGESTION'); + assertActivityGroupDetails('DELETE_SUGGESTION', ['Navržený překlad']); }); it('reviewer can accept his own suggestion', () => { @@ -166,10 +164,8 @@ describe('Suggestions reviewer', () => { assertMessage('Suggestion accepted, other variants declined (1)'); visitProjectDashboard(projectId); - gcyAdvanced({ - value: 'activity-compact', - type: 'ACCEPT_SUGGESTION', - }).should('contain', 'Navržený překlad 0-1'); + expandActivityGroup('ACCEPT_SUGGESTION'); + assertActivityGroupDetails('ACCEPT_SUGGESTION', ['Navržený překlad 0-1']); }); function acceptSuggestion() { diff --git a/e2e/cypress/e2e/translations/outdated.cy.ts b/e2e/cypress/e2e/translations/outdated.cy.ts index a481561e538..badadf1c702 100644 --- a/e2e/cypress/e2e/translations/outdated.cy.ts +++ b/e2e/cypress/e2e/translations/outdated.cy.ts @@ -1,7 +1,11 @@ import { ProjectDTO } from '../../../../webapp/src/service/response.types'; import { deleteProject } from '../../common/apiCalls/common'; import { waitForGlobalLoading } from '../../common/loading'; -import { assertMessage, visitProjectDashboard } from '../../common/shared'; +import { + gcyAdvanced, + assertMessage, + visitProjectDashboard, +} from '../../common/shared'; import { create4Translations, @@ -46,8 +50,10 @@ describe('Translation states', () => { getRemoveOutdatedIndicator('Studený přeložený text 1').click(); visitProjectDashboard(project.id); - const lastActivity = cy.gcy('activity-compact').first(); - lastActivity.contains('Updated state').should('be.visible'); + gcyAdvanced({ + value: 'activity-group-item', + type: 'SET_OUTDATED_FLAG', + }).should('be.visible'); }); it("won't mark empty translation", () => { diff --git a/e2e/cypress/e2e/translations/translationLabels.cy.ts b/e2e/cypress/e2e/translations/translationLabels.cy.ts index 4144aeed0b4..65592afd686 100644 --- a/e2e/cypress/e2e/translations/translationLabels.cy.ts +++ b/e2e/cypress/e2e/translations/translationLabels.cy.ts @@ -8,7 +8,10 @@ import { dismissMenu, gcy } from '../../common/shared'; import { isDarkMode } from '../../common/helpers'; import { E2TranslationLabel } from '../../compounds/E2TranslationLabel'; import { E2TranslationsView } from '../../compounds/E2TranslationsView'; -import { assertActivityDetails, checkActivity } from '../../common/activities'; +import { + assertActivityGroupDetails, + checkActivityGroup, +} from '../../common/activities'; import { setFeature } from '../../common/features'; import { findBatchOperation, @@ -155,9 +158,8 @@ describe('Projects Settings - Labels', () => { 4 ); - checkActivity('Translation labels updated'); - assertActivityDetails([ - 'Translation labels updated', + checkActivityGroup('SET_TRANSLATION_LABELS'); + assertActivityGroupDetails('SET_TRANSLATION_LABELS', [ 'first key', 'label to assign 1', ]); @@ -173,8 +175,8 @@ describe('Projects Settings - Labels', () => { 'First label' ); - checkActivity('Translation labels updated'); - assertActivityDetails(['Translation labels updated', 'first key']); + checkActivityGroup('SET_TRANSLATION_LABELS'); + assertActivityGroupDetails('SET_TRANSLATION_LABELS', ['first key']); }); it('adds labels to translations and sorts them alphabetically', () => { diff --git a/webapp/src/component/activity/groups/GenericGroupExpandedContent.tsx b/webapp/src/component/activity/groups/GenericGroupExpandedContent.tsx index 8711e2ee1b0..83627bc6b3f 100644 --- a/webapp/src/component/activity/groups/GenericGroupExpandedContent.tsx +++ b/webapp/src/component/activity/groups/GenericGroupExpandedContent.tsx @@ -33,6 +33,11 @@ const StyledLanguage = styled('span')` color: ${({ theme }) => theme.palette.text.secondary}; `; +const StyledSecondary = styled('div')` + color: ${({ theme }) => theme.palette.text.secondary}; + font-size: 13px; +`; + const MAX_DISPLAYED_MODIFICATIONS = 3; const MAX_VALUE_LENGTH = 60; @@ -58,9 +63,14 @@ export const GenericGroupExpandedContent: FC<{ groupId: number }> = (props) => { {item.entityClass} - {getTitle(item)} - {getLanguageTag(item) && ( - ({getLanguageTag(item)}) +
+ {getTitle(item)} + {getLanguageTag(item) && ( + ({getLanguageTag(item)}) + )} +
+ {getSubtitle(item) && ( + {getSubtitle(item)} )}
@@ -141,6 +151,25 @@ function getTitle(item: GenericGroupItemModel): string { return `#${item.entityId}`; } +const SUBTITLE_FIELDS = ['translation', 'text', 'description']; + +/** + * The entity's own content, when the title had to be taken from a relation + * (e.g. a suggestion titled by its key still wants to show the suggested text). + */ +function getSubtitle(item: GenericGroupItemModel): string | undefined { + const title = getTitle(item); + + for (const field of SUBTITLE_FIELDS) { + const described = item.description?.[field]; + if (typeof described === 'string' && described && described !== title) { + return described; + } + } + + return undefined; +} + function getLanguageTag(item: GenericGroupItemModel): string | undefined { const tag = item.relations?.language?.data?.tag; return typeof tag === 'string' ? tag : undefined;