mirror of
https://github.com/makeplane/plane.git
synced 2026-02-25 04:35:21 +01:00
[SILO-28] Chore: Gitlab integration UI and backend changes (#2071)
* chore: gitlab integration add project and group APIs * entity connection schema changes + gitlab integration UI and store changes * gitlab integration UI + APIs for entity connections * Merge branch 'preview' into chore-gitlab_integration_ui * Merge branch 'preview' into chore-gitlab_integration_ui * gitlab webhook * sharedwithgroups key in gitlab merge request type * chore: gitlab update issue based on project connection * chore: gitlab integration * merged with preview * merged with preview * yarn fix
This commit is contained in:
@@ -34,6 +34,8 @@ export type TGitlabWorkspaceConnectionType = keyof typeof EGitlabWorkspaceConnec
|
||||
|
||||
export type TGitlabWorkspaceConnectionData = {
|
||||
id: number | undefined;
|
||||
name: string | undefined;
|
||||
organization: string | undefined;
|
||||
url: string | undefined;
|
||||
type: string | undefined;
|
||||
login: string | undefined;
|
||||
|
||||
@@ -100,4 +100,80 @@ export class GitLabService {
|
||||
const response = await this.client.get(`/projects/${projectId}/members`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async addWebhookToProject(projectId: string, url: string, token: string) {
|
||||
try {
|
||||
const response = await this.client.post(
|
||||
`/projects/${projectId}/hooks`,
|
||||
{ url, token, push_events: true, merge_requests_events: true, pipeline_events: true, tag_push_events: true, issues_events: true },
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param projectId - entityId or gitlab project id
|
||||
* @param hookId - webhookId or gitlab hook id
|
||||
* @returns
|
||||
*/
|
||||
async removeWebhookFromProject(projectId: string, hookId: string) {
|
||||
try {
|
||||
const response = await this.client.delete(
|
||||
`/projects/${projectId}/hooks/${hookId}`
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async addWebhookToGroup(groupId: string, url: string, token: string) {
|
||||
try {
|
||||
const response = await this.client.post(
|
||||
`/groups/${groupId}/hooks`,
|
||||
{ url, token, push_events: true, merge_requests_events: true, pipeline_events: true, tag_push_events: true, issues_events: true },
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param groupId - entityId or gitlab group id
|
||||
* @param hookId - webhookId or gitlab hook id
|
||||
* @returns
|
||||
*/
|
||||
async removeWebhookFromGroup(groupId: string, hookId: string) {
|
||||
try {
|
||||
const response = await this.client.delete(
|
||||
`/groups/${groupId}/hooks/${hookId}`
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async getGroups() {
|
||||
try {
|
||||
const response = await this.client.get("/groups");
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async getProjects() {
|
||||
try {
|
||||
const response = await this.client.get("/projects?membership=true&pages=100");
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import axios from "axios";
|
||||
import crypto from 'crypto';
|
||||
import { GitLabAuthConfig, GitLabAuthorizeState, GitLabAuthPayload, GitLabTokenResponse } from "../types/auth";
|
||||
|
||||
const DEFAULT_SCOPES = ["api", "read_api", "read_user", "read_repository", "profile", "email"];
|
||||
@@ -51,4 +52,55 @@ export class GitLabAuthService {
|
||||
|
||||
return { response, state: decodedState };
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param workspaceId
|
||||
* @returns workspace webhook secret
|
||||
*/
|
||||
|
||||
getWorkspaceWebhookSecret(workspaceId: string) {
|
||||
try {
|
||||
const GITLAB_CLIENT_SECRET = this.config.clientSecret;
|
||||
if (!GITLAB_CLIENT_SECRET) {
|
||||
throw new Error("GITLAB_CLIENT_SECRET is not defined");
|
||||
}
|
||||
|
||||
if (!workspaceId) {
|
||||
throw new Error("workspaceId is not defined");
|
||||
}
|
||||
|
||||
// Combine the strings with a delimiter (e.g., ":")
|
||||
const combined = `${workspaceId}:${GITLAB_CLIENT_SECRET}`;
|
||||
|
||||
// Hash the combined string using SHA-256
|
||||
const hash = crypto.createHash('sha256').update(combined).digest('hex');
|
||||
|
||||
// Return the first 32 characters of the hash
|
||||
return hash.slice(0, 32);
|
||||
} catch (error) {
|
||||
console.error("error getWorkspaceWebhookSecret", error);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param workspaceId
|
||||
* @param webhookSecret
|
||||
* @returns boolean
|
||||
*/
|
||||
verifyGitlabWebhookSecret(workspaceId: string, webhookSecret: string) {
|
||||
try {
|
||||
const webhookHash = this.getWorkspaceWebhookSecret(workspaceId);
|
||||
if (!webhookHash) return false;
|
||||
return webhookHash === webhookSecret;
|
||||
} catch (error) {
|
||||
console.error("error verifyGitlabWebhookSecret", error);
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -70,6 +70,10 @@ export interface GitlabProject {
|
||||
kind: string;
|
||||
full_path: string;
|
||||
};
|
||||
shared_with_groups: {
|
||||
group_id: number;
|
||||
group_name: string;
|
||||
}[];
|
||||
default_branch: string;
|
||||
visibility: "private" | "internal" | "public";
|
||||
}
|
||||
@@ -147,3 +151,31 @@ export interface GitlabNote {
|
||||
imported?: boolean;
|
||||
imported_from?: string;
|
||||
}
|
||||
|
||||
export interface GitlabWebhook {
|
||||
url: string;
|
||||
token: string;
|
||||
}
|
||||
|
||||
export interface GitlabEntityData {
|
||||
id: string;
|
||||
type: string;
|
||||
webhookId: string;
|
||||
}
|
||||
|
||||
export enum GitlabEntityType {
|
||||
PROJECT = "PROJECT",
|
||||
GROUP = "GROUP",
|
||||
}
|
||||
|
||||
export interface IGitlabEntity {
|
||||
id: string;
|
||||
name: string;
|
||||
type: GitlabEntityType;
|
||||
}
|
||||
|
||||
|
||||
export enum EConnectionType {
|
||||
ENTITY = "ENTITY",
|
||||
PLANE_PROJECT = "PLANE_PROJECT",
|
||||
}
|
||||
@@ -2,9 +2,12 @@ import { Request, Response } from "express";
|
||||
import { Controller, Get, Post, Put, Delete } from "@/lib";
|
||||
import {
|
||||
createEntityConnectionByWorkspaceConnectionId,
|
||||
deleteEntityConnection,
|
||||
deleteEntityConnectionByWorkspaceConnectionIdAndEntityId,
|
||||
getEntityConnection,
|
||||
getEntityConnectionByWorkspaceIdAndConnectionId,
|
||||
getEntityConnectionByWorkspaceIdAndConnectionIdAndEntityId,
|
||||
updateEntityConnection,
|
||||
updateEntityConnectionByWorkspaceConnectionIdAndEntityId,
|
||||
} from "@/db/query/connection";
|
||||
|
||||
@@ -128,6 +131,80 @@ export class EntityConnectionController {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Get("/:id")
|
||||
async getEntityConnectionByConnectionId(req: Request, res: Response) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
if (!id) {
|
||||
return res.status(400).send({
|
||||
message: "Bad Request, expected id to be present.",
|
||||
});
|
||||
}
|
||||
|
||||
const entityConnections = await getEntityConnection(id);
|
||||
|
||||
return res.status(200).send(entityConnections);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(500).send("Internal Server Error");
|
||||
}
|
||||
}
|
||||
|
||||
@Put("/:id")
|
||||
async updateEntityConnectionById(req: Request, res: Response) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
if (!id) {
|
||||
return res.status(400).send({
|
||||
message: "Bad Request, expected id to be present.",
|
||||
});
|
||||
}
|
||||
|
||||
const payload = {
|
||||
workspaceSlug: req.body.workspaceSlug,
|
||||
projectId: req.body.projectId,
|
||||
entityId: req.body.entityId,
|
||||
entitySlug: req.body.entitySlug,
|
||||
entityData: req.body.entityData,
|
||||
config: req.body.config,
|
||||
};
|
||||
|
||||
const entityConnections = await updateEntityConnection(
|
||||
id,
|
||||
payload
|
||||
);
|
||||
|
||||
return res.status(200).send(entityConnections);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(500).send("Internal Server Error");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Delete("/:id")
|
||||
async deleteEntityConnectionById(req: Request, res: Response) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
if (!id) {
|
||||
return res.status(400).send({
|
||||
message: "Bad Request, expected id to be present.",
|
||||
});
|
||||
}
|
||||
|
||||
const entityConnections = await deleteEntityConnection(id);
|
||||
|
||||
return res.status(200).send(entityConnections);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(500).send("Internal Server Error");
|
||||
}
|
||||
}
|
||||
|
||||
@Delete("/:workspaceId/:workspaceConnectionId/:entityId")
|
||||
async deleteEntityConnection(req: Request, res: Response) {
|
||||
try {
|
||||
|
||||
@@ -80,14 +80,14 @@ export const syncCommentWithPlane = async (
|
||||
workspaceConnection.config.userMap.map((obj) => [obj.githubUser.login, obj.planeUser.id])
|
||||
);
|
||||
|
||||
const planeUsers = await planeClient.users.list(entityConnection.workspaceSlug, entityConnection.projectId);
|
||||
const planeUsers = await planeClient.users.list(entityConnection.workspaceSlug, entityConnection.projectId ?? "");
|
||||
|
||||
let comment: ExIssueComment | null = null;
|
||||
|
||||
try {
|
||||
comment = await planeClient.issueComment.getIssueCommentWithExternalId(
|
||||
entityConnection.workspaceSlug,
|
||||
entityConnection.projectId,
|
||||
entityConnection.projectId ?? "",
|
||||
issue.id,
|
||||
data.comment.id.toString(),
|
||||
"GITHUB"
|
||||
@@ -101,7 +101,7 @@ export const syncCommentWithPlane = async (
|
||||
issue.id,
|
||||
data.repository.full_name,
|
||||
entityConnection.workspaceSlug,
|
||||
entityConnection.projectId,
|
||||
entityConnection.projectId ?? "",
|
||||
planeClient,
|
||||
ghService,
|
||||
userMap,
|
||||
@@ -112,7 +112,7 @@ export const syncCommentWithPlane = async (
|
||||
if (comment) {
|
||||
await planeClient.issueComment.update(
|
||||
entityConnection.workspaceSlug,
|
||||
entityConnection.projectId,
|
||||
entityConnection.projectId ?? "",
|
||||
issue.id,
|
||||
comment.id,
|
||||
planeComment
|
||||
@@ -121,7 +121,7 @@ export const syncCommentWithPlane = async (
|
||||
} else {
|
||||
const createdComment = await planeClient.issueComment.create(
|
||||
entityConnection.workspaceSlug,
|
||||
entityConnection.projectId,
|
||||
entityConnection.projectId ?? "",
|
||||
issue.id,
|
||||
planeComment
|
||||
);
|
||||
@@ -137,7 +137,7 @@ const getPlaneIssue = async (planeClient: PlaneClient, entityConnection: GithubE
|
||||
try {
|
||||
return await planeClient.issue.getIssueWithExternalId(
|
||||
entityConnection.workspaceSlug,
|
||||
entityConnection.projectId,
|
||||
entityConnection.projectId ?? "",
|
||||
issueId.toString(),
|
||||
"GITHUB"
|
||||
);
|
||||
|
||||
@@ -83,13 +83,13 @@ export const syncIssueWithPlane = async (store: Store, data: GithubIssueDedupPay
|
||||
try {
|
||||
issue = await planeClient.issue.getIssueWithExternalId(
|
||||
entityConnection.workspaceSlug,
|
||||
entityConnection.projectId,
|
||||
entityConnection.projectId ?? "",
|
||||
data.issueNumber.toString(),
|
||||
"GITHUB"
|
||||
);
|
||||
} catch (error) { }
|
||||
|
||||
const planeUsers = await planeClient.users.list(entityConnection.workspaceSlug, entityConnection.projectId);
|
||||
const planeUsers = await planeClient.users.list(entityConnection.workspaceSlug, entityConnection.projectId ?? "");
|
||||
|
||||
const userMap: Record<string, string> = Object.fromEntries(
|
||||
workspaceConnection.config.userMap.map((obj) => [obj.githubUser.login, obj.planeUser.id])
|
||||
@@ -103,14 +103,14 @@ export const syncIssueWithPlane = async (store: Store, data: GithubIssueDedupPay
|
||||
data.repositoryName,
|
||||
userMap,
|
||||
entityConnection.workspaceSlug,
|
||||
entityConnection.projectId,
|
||||
entityConnection.projectId ?? "",
|
||||
planeUsers,
|
||||
ghService,
|
||||
issue ? true : false
|
||||
);
|
||||
|
||||
const states = (await planeClient.state.list(entityConnection.workspaceSlug, entityConnection.projectId)).results;
|
||||
const users = await planeClient.users.list(entityConnection.workspaceSlug, entityConnection.projectId);
|
||||
const states = (await planeClient.state.list(entityConnection.workspaceSlug, entityConnection.projectId ?? "")).results;
|
||||
const users = await planeClient.users.list(entityConnection.workspaceSlug, entityConnection.projectId ?? "");
|
||||
|
||||
if (planeIssue.state) {
|
||||
const state = states.find((s) => s.name === planeIssue.state);
|
||||
@@ -120,7 +120,7 @@ export const syncIssueWithPlane = async (store: Store, data: GithubIssueDedupPay
|
||||
}
|
||||
|
||||
if (planeIssue.labels) {
|
||||
const labels = (await planeClient.label.list(entityConnection.workspaceSlug, entityConnection.projectId)).results;
|
||||
const labels = (await planeClient.label.list(entityConnection.workspaceSlug, entityConnection.projectId ?? "")).results;
|
||||
const githubLabel = labels.find((l) => l.name.toLowerCase() === "github");
|
||||
|
||||
if (githubLabel) {
|
||||
@@ -137,7 +137,7 @@ export const syncIssueWithPlane = async (store: Store, data: GithubIssueDedupPay
|
||||
const labelPromises = labelsToCreate.map(async (label: any) => {
|
||||
const createdLabel = await planeClient.label.create(
|
||||
entityConnection.workspaceSlug,
|
||||
entityConnection.projectId,
|
||||
entityConnection.projectId ?? "",
|
||||
{
|
||||
name: label.name,
|
||||
color: `#${label.color}`,
|
||||
@@ -182,12 +182,12 @@ export const syncIssueWithPlane = async (store: Store, data: GithubIssueDedupPay
|
||||
}
|
||||
|
||||
if (issue) {
|
||||
await planeClient.issue.update(entityConnection.workspaceSlug, entityConnection.projectId, issue.id, planeIssue);
|
||||
await planeClient.issue.update(entityConnection.workspaceSlug, entityConnection.projectId ?? "", issue.id, planeIssue);
|
||||
await store.set(`silo:issue:${issue.id}`, "true");
|
||||
} else {
|
||||
const createdIssue = await planeClient.issue.create(
|
||||
entityConnection.workspaceSlug,
|
||||
entityConnection.projectId,
|
||||
entityConnection.projectId ?? "",
|
||||
planeIssue
|
||||
);
|
||||
|
||||
@@ -195,12 +195,12 @@ export const syncIssueWithPlane = async (store: Store, data: GithubIssueDedupPay
|
||||
const createLink = async () => {
|
||||
const linkTitle = `[${entityConnection.entitySlug}] ${ghIssue?.data.title} #${ghIssue?.data.number}`;
|
||||
const linkUrl = ghIssue?.data.html_url;
|
||||
await planeClient.issue.createLink(entityConnection.workspaceSlug, entityConnection.projectId, createdIssue.id, linkTitle, linkUrl);
|
||||
await planeClient.issue.createLink(entityConnection.workspaceSlug, entityConnection.projectId ?? "", createdIssue.id, linkTitle, linkUrl);
|
||||
}
|
||||
|
||||
const createLinkBack = async () => {
|
||||
// Get the project for the issue
|
||||
const project = await planeClient.project.getProject(entityConnection.workspaceSlug, entityConnection.projectId);
|
||||
const project = await planeClient.project.getProject(entityConnection.workspaceSlug, entityConnection.projectId ?? "");
|
||||
const comment = `Synced Issue with [Plane](${env.APP_BASE_URL}) Workspace 🔄\n\n[${project.identifier}-${createdIssue.sequence_id} ${createdIssue.name}](${env.APP_BASE_URL}/${entityConnection.workspaceSlug}/projects/${entityConnection.projectId}/issues/${createdIssue.id})`;
|
||||
await ghService.createIssueComment(data.owner, data.repositoryName, Number(data.issueNumber), comment);
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ const handlePullRequestOpened = async (data: GithubWebhookPayload["webhook-pull-
|
||||
try {
|
||||
const issue = await planeClient.issue.getIssueWithExternalId(
|
||||
entityConnection.workspaceSlug,
|
||||
entityConnection.projectId,
|
||||
entityConnection.projectId ?? "",
|
||||
reference.node.databaseId.toString(),
|
||||
"GITHUB"
|
||||
);
|
||||
@@ -68,7 +68,7 @@ const handlePullRequestOpened = async (data: GithubWebhookPayload["webhook-pull-
|
||||
// Create a link in the issue for the pull request
|
||||
await planeClient.issue.createLink(
|
||||
entityConnection.workspaceSlug,
|
||||
entityConnection.projectId,
|
||||
entityConnection.projectId ?? "",
|
||||
issue.id,
|
||||
`GitHub PR: ${data.pull_request.title}`,
|
||||
data.pull_request.html_url
|
||||
|
||||
@@ -50,7 +50,7 @@ const handleCommentSync = async (store: Store, payload: PlaneWebhookPayload) =>
|
||||
// Get the issue associated with the comment
|
||||
const issue = await planeClient.issue.getIssue(
|
||||
entityConnection.workspaceSlug,
|
||||
entityConnection.projectId,
|
||||
entityConnection.projectId ?? "",
|
||||
payload.issue
|
||||
);
|
||||
|
||||
@@ -66,7 +66,7 @@ const handleCommentSync = async (store: Store, payload: PlaneWebhookPayload) =>
|
||||
|
||||
const comment = await planeClient.issueComment.getComment(
|
||||
entityConnection.workspaceSlug,
|
||||
entityConnection.projectId,
|
||||
entityConnection.projectId ?? "",
|
||||
payload.issue,
|
||||
payload.id
|
||||
);
|
||||
@@ -88,7 +88,7 @@ const handleCommentSync = async (store: Store, payload: PlaneWebhookPayload) =>
|
||||
) {
|
||||
await planeClient.issueComment.update(
|
||||
entityConnection.workspaceSlug,
|
||||
entityConnection.projectId,
|
||||
entityConnection.projectId ?? "",
|
||||
payload.issue,
|
||||
payload.id,
|
||||
{
|
||||
@@ -110,8 +110,8 @@ const createOrUpdateGitHubComment = async (
|
||||
entityConnection: GithubEntityConnection,
|
||||
credentials: TServiceCredentials
|
||||
) => {
|
||||
const owner = entityConnection.entitySlug.split("/")[0];
|
||||
const repo = entityConnection.entitySlug.split("/")[1];
|
||||
const owner = (entityConnection.entitySlug ?? "").split("/")[0];
|
||||
const repo = (entityConnection.entitySlug ?? "").split("/")[1];
|
||||
|
||||
const assetImagePrefix = imagePrefix + workspaceConnection.workspaceId + "/" + credentials.user_id;
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ const handleIssueSync = async (store: Store, payload: PlaneWebhookPayload) => {
|
||||
|
||||
const issue = await planeClient.issue.getIssue(entityConnection.workspaceSlug, payload.project, payload.id);
|
||||
|
||||
const labels = await planeClient.label.list(entityConnection.workspaceSlug, entityConnection.projectId);
|
||||
const labels = await planeClient.label.list(entityConnection.workspaceSlug, entityConnection.projectId ?? "");
|
||||
const githubIssue = await createOrUpdateGitHubIssue(
|
||||
githubService,
|
||||
planeClient,
|
||||
@@ -73,7 +73,7 @@ const handleIssueSync = async (store: Store, payload: PlaneWebhookPayload) => {
|
||||
if (!issue.external_id || !issue.external_source || (issue.external_source && issue.external_source !== "GITHUB")) {
|
||||
// Add the external id and source
|
||||
const addExternalId = async () => {
|
||||
await planeClient.issue.update(entityConnection.workspaceSlug, entityConnection.projectId, payload.id, {
|
||||
await planeClient.issue.update(entityConnection.workspaceSlug, entityConnection.projectId ?? "", payload.id, {
|
||||
external_id: githubIssue?.data.number.toString(),
|
||||
external_source: "GITHUB",
|
||||
});
|
||||
@@ -83,14 +83,8 @@ const handleIssueSync = async (store: Store, payload: PlaneWebhookPayload) => {
|
||||
const createLink = async () => {
|
||||
const linkTitle = `[${entityConnection.entitySlug}] ${githubIssue?.data.title} #${githubIssue?.data.number}`;
|
||||
const linkUrl = githubIssue?.data.html_url;
|
||||
await planeClient.issue.createLink(
|
||||
entityConnection.workspaceSlug,
|
||||
entityConnection.projectId,
|
||||
issue.id,
|
||||
linkTitle,
|
||||
linkUrl
|
||||
);
|
||||
};
|
||||
await planeClient.issue.createLink(entityConnection.workspaceSlug, entityConnection.projectId ?? "", issue.id, linkTitle, linkUrl);
|
||||
}
|
||||
|
||||
// Execute all the promises
|
||||
await Promise.all([addExternalId(), createLink()]);
|
||||
@@ -118,9 +112,9 @@ const createOrUpdateGitHubIssue = async (
|
||||
workspaceConnection.config.userMap.map((obj) => [obj.planeUser.id, obj.githubUser])
|
||||
);
|
||||
|
||||
const owner = entityConnection.entitySlug.split("/")[0];
|
||||
const repo = entityConnection.entitySlug.split("/")[1];
|
||||
const issueImagePrefix = imagePrefix + workspaceConnection.workspaceId + "/" + credentials.user_id;
|
||||
const owner = (entityConnection.entitySlug ?? "").split("/")[0];
|
||||
const repo = (entityConnection.entitySlug ?? "").split("/")[1];
|
||||
const issueImagePrefix = imagePrefix + workspaceConnection.workspaceId + "/" + credentials.user_id
|
||||
|
||||
const transformedGithubIssue = await transformPlaneIssue(issue, issueImagePrefix, labels, owner, repo, userMap);
|
||||
|
||||
@@ -146,7 +140,7 @@ const createOrUpdateGitHubIssue = async (
|
||||
} else {
|
||||
const createdIssue = await githubUserService.createIssue(transformedGithubIssue as GithubIssue);
|
||||
|
||||
const project = await planeClient.project.getProject(entityConnection.workspaceSlug, entityConnection.projectId);
|
||||
const project = await planeClient.project.getProject(entityConnection.workspaceSlug, entityConnection.projectId ?? "");
|
||||
|
||||
const comment = `Synced Issue with [Plane](${env.APP_BASE_URL}) Workspace 🔄\n\n[${project.identifier}-${issue.sequence_id} ${issue.name}](${env.APP_BASE_URL}/${entityConnection.workspaceSlug}/projects/${entityConnection.projectId}/issues/${issue.id})`;
|
||||
await githubService.createIssueComment(owner, repo, Number(createdIssue.data.number), comment);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { importTaskManger, integrationTaskManager } from "@/apps/engine/worker";
|
||||
import { env } from "@/env";
|
||||
import { Controller, Get, Post } from "@/lib";
|
||||
import { Controller, Delete, Get, Post } from "@/lib";
|
||||
import { ExIssueLabel } from "@plane/sdk";
|
||||
import { Request, Response } from "express";
|
||||
import { createGitLabAuth, createGitLabService, GitlabWebhookEvent } from "@plane/etl/gitlab";
|
||||
import { createGitLabAuth, createGitLabService, GitlabWebhookEvent, GitlabWebhook, GitlabEntityType, IGitlabEntity, GitlabEntityData, EConnectionType } from "@plane/etl/gitlab";
|
||||
import { verifyGitlabToken } from "../helpers";
|
||||
import { createOrUpdateCredentials, getCredentialsByOnlyWorkspaceId, deleteCredentialsForWorkspace } from "@/db/query";
|
||||
import {
|
||||
@@ -12,8 +12,18 @@ import {
|
||||
updateWorkspaceConnection,
|
||||
deleteEntityConnectionByWorkspaceConnectionId,
|
||||
deleteWorkspaceConnection,
|
||||
createEntityConnectionByWorkspaceConnectionId,
|
||||
getEntityConnectionByWorkspaceIdAndConnectionIdAndEntityId,
|
||||
getEntityConnectionByEntityId,
|
||||
getEntityConnectionByWorkspaceIdAndConnectionId,
|
||||
deleteEntityConnection,
|
||||
getEntityConnection,
|
||||
getEntityConnectionByWorkspaceAndProjectId,
|
||||
getEntityConnectionByWorkspaceConnectionAndProjectId,
|
||||
} from "@/db/query/connection";
|
||||
import { logger } from "@/logger";
|
||||
import { EIntegrationType } from "@/types";
|
||||
import { gitlabAuthService, getGitlabClientService } from "../services";
|
||||
|
||||
@Controller("/api/gitlab")
|
||||
export class GitlabController {
|
||||
@@ -168,7 +178,7 @@ export class GitlabController {
|
||||
});
|
||||
}
|
||||
|
||||
res.send({ message: "Successfully connected to GitLab" });
|
||||
res.redirect(`${env.APP_BASE_URL}/${authState.workspace_slug}/settings/integrations/gitlab/`);
|
||||
}
|
||||
|
||||
@Post("/gitlab-webhook")
|
||||
@@ -243,4 +253,231 @@ export class GitlabController {
|
||||
Number(env.DEDUP_INTERVAL)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@Post("/entity-connections/:workspaceId/:workspaceConnectionId")
|
||||
async addEntityConnection(req: Request, res: Response, next: any) {
|
||||
try {
|
||||
const { workspaceId, workspaceConnectionId } = req.params;
|
||||
const { entityId, entityType, workspaceSlug, entitySlug } = req.body;
|
||||
|
||||
if (!workspaceId || !workspaceConnectionId || !entityId || !entityType || !workspaceSlug || !entitySlug) {
|
||||
return res.status(400).send({
|
||||
message: "Bad Request, expected workspaceId, workspaceConnectionId, and entityId to be present.",
|
||||
});
|
||||
}
|
||||
|
||||
// Check for existing connections
|
||||
const connections = await getEntityConnectionByWorkspaceIdAndConnectionIdAndEntityId(
|
||||
workspaceId,
|
||||
workspaceConnectionId,
|
||||
entityId
|
||||
);
|
||||
|
||||
if (connections.length > 0) {
|
||||
return res.status(201).json({ error: "Entity connection already exists" });
|
||||
}
|
||||
|
||||
|
||||
// Add webhook to gitlab
|
||||
const { url, token } = this.getWorkspaceWebhookData(workspaceId)
|
||||
const gitlabClientService = await getGitlabClientService(workspaceId)
|
||||
|
||||
// based on enum either add to project or group
|
||||
let webhookId;
|
||||
console.log("inside add webhook to project", entityType, entityId, url, token)
|
||||
if (entityType === GitlabEntityType.PROJECT) {
|
||||
const { id: hookId } = await gitlabClientService.addWebhookToProject(entityId, url, token);
|
||||
webhookId = hookId;
|
||||
} else {
|
||||
const { id: hookId } = await gitlabClientService.addWebhookToGroup(entityId, url, token);
|
||||
webhookId = hookId;
|
||||
}
|
||||
|
||||
const connection = await createEntityConnectionByWorkspaceConnectionId(
|
||||
workspaceId,
|
||||
workspaceConnectionId,
|
||||
{
|
||||
workspaceId,
|
||||
workspaceConnectionId,
|
||||
connectionType: EConnectionType.ENTITY,
|
||||
workspaceSlug,
|
||||
entityId,
|
||||
entitySlug,
|
||||
entityData: {
|
||||
id: entityId,
|
||||
type: entityType,
|
||||
webhookId
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
res.status(200).json(connection);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
@Post("/entity-project-connections/:workspaceId/:workspaceConnectionId")
|
||||
async addProjectConnection(req: Request, res: Response, next: any) {
|
||||
try {
|
||||
const { workspaceId, workspaceConnectionId } = req.params;
|
||||
const { projectId, workspaceSlug, config } = req.body;
|
||||
|
||||
if (!workspaceId || !workspaceConnectionId || !projectId || !workspaceSlug) {
|
||||
return res.status(400).send({
|
||||
message: "Bad Request, expected workspaceId, workspaceConnectionId, and projectId to be present.",
|
||||
});
|
||||
}
|
||||
|
||||
// Check for existing connections
|
||||
const connections = await getEntityConnectionByWorkspaceConnectionAndProjectId(
|
||||
workspaceId,
|
||||
projectId
|
||||
);
|
||||
|
||||
if (connections.length > 0) {
|
||||
return res.status(201).json({ error: "Entity connection already exists" });
|
||||
}
|
||||
|
||||
const connection = await createEntityConnectionByWorkspaceConnectionId(
|
||||
workspaceId,
|
||||
workspaceConnectionId,
|
||||
{
|
||||
workspaceId,
|
||||
workspaceConnectionId,
|
||||
connectionType: EConnectionType.PLANE_PROJECT,
|
||||
projectId,
|
||||
workspaceSlug,
|
||||
config
|
||||
}
|
||||
);
|
||||
|
||||
res.status(200).json(connection);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
@Delete("/entity-connections/:workspaceId/:connectionId")
|
||||
async removeEntityConnection(req: Request, res: Response, next: any) {
|
||||
try {
|
||||
const { workspaceId, connectionId } = req.params;
|
||||
|
||||
const [entityConnection] = await getEntityConnection(connectionId);
|
||||
if (!entityConnection) {
|
||||
return res.status(400).json({ error: "Entity connection not found" });
|
||||
}
|
||||
|
||||
const gitlabClientService = await getGitlabClientService(workspaceId)
|
||||
const entityData = entityConnection.entityData as GitlabEntityData
|
||||
|
||||
if (entityData.type === GitlabEntityType.PROJECT) {
|
||||
await gitlabClientService.removeWebhookFromProject(entityData.id, entityData.webhookId);
|
||||
} else if (entityData.type === GitlabEntityType.GROUP) {
|
||||
await gitlabClientService.removeWebhookFromGroup(entityData.id, entityData.webhookId);
|
||||
}
|
||||
|
||||
const connection = await deleteEntityConnection(connectionId);
|
||||
res.status(200).json(connection);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Post("/webhook/:workspaceId")
|
||||
async webhook(req: Request, res: Response, next: any) {
|
||||
try {
|
||||
const workspaceId = req.params.workspaceId;
|
||||
const webhookSecret = req.headers["x-gitlab-token"]?.toString();
|
||||
|
||||
if (!gitlabAuthService.verifyGitlabWebhookSecret(workspaceId, webhookSecret ?? "")) {
|
||||
return res.status(400).send({
|
||||
message: "Webhook received",
|
||||
});
|
||||
} else {
|
||||
res.status(202).send({
|
||||
message: "Webhook received",
|
||||
});
|
||||
|
||||
const webhookEvent = req.body as GitlabWebhookEvent;
|
||||
|
||||
// Generate a unique job ID
|
||||
const jobId = `gitlab-${webhookEvent.object_kind}-${Date.now()}`;
|
||||
|
||||
// Forward the event to the task manager to process
|
||||
await integrationTaskManager.registerTask(
|
||||
{
|
||||
route: "gitlab-webhook",
|
||||
jobId: jobId,
|
||||
type: webhookEvent.object_kind,
|
||||
},
|
||||
webhookEvent
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Get("/entity-connections/:workspaceId")
|
||||
async getAllEntityConnections(req: Request, res: Response, next: any) {
|
||||
try {
|
||||
const workspaceId = req.params.workspaceId;
|
||||
const [workspaceConnections] = await getWorkspaceConnections(workspaceId, EIntegrationType.GITLAB);
|
||||
const entityConnections = await getEntityConnectionByWorkspaceIdAndConnectionId(workspaceId, workspaceConnections.id);
|
||||
res.status(200).json(entityConnections);
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
@Get("/entities/:workspaceId")
|
||||
async getProjectAndGroups(req: Request, res: Response, next: any) {
|
||||
try {
|
||||
const workspaceId = req.params.workspaceId;
|
||||
const entities = [];
|
||||
const gitlabClientService = await getGitlabClientService(workspaceId)
|
||||
const [projects, groups] = await Promise.all([
|
||||
gitlabClientService.getProjects(),
|
||||
gitlabClientService.getGroups(),
|
||||
]);
|
||||
|
||||
if (projects.length) {
|
||||
entities.push(...projects.map((project: IGitlabEntity) => ({ id: project.id, name: project.name, type: GitlabEntityType.PROJECT })));
|
||||
}
|
||||
|
||||
if (groups.length) {
|
||||
entities.push(...groups.map((group: IGitlabEntity) => ({ id: group.id, name: group.name, type: GitlabEntityType.GROUP })));
|
||||
}
|
||||
res.status(200).json(entities);
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
getWorkspaceWebhookData(workspaceId: string) {
|
||||
try {
|
||||
if (!workspaceId) {
|
||||
throw new Error("workspaceId is not defined");
|
||||
}
|
||||
const workspaceWebhookSecret = gitlabAuthService.getWorkspaceWebhookSecret(workspaceId);
|
||||
const webhookURL = `${env.SILO_API_BASE_URL}/silo/api/gitlab/webhook/${workspaceId}`;
|
||||
const gitlabWebhook: GitlabWebhook = {
|
||||
url: webhookURL,
|
||||
token: workspaceWebhookSecret,
|
||||
};
|
||||
return gitlabWebhook;
|
||||
} catch (error) {
|
||||
console.error("error getWorkspaceWebhook", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,20 +1,28 @@
|
||||
import {
|
||||
EConnectionType,
|
||||
gitlabEntityConnectionSchema,
|
||||
GitlabMergeRequestEvent,
|
||||
gitlabWorkspaceConnectionSchema,
|
||||
MergeRequestEvent,
|
||||
} from "@plane/etl/gitlab";
|
||||
import { GitlabConnectionDetails } from "../types";
|
||||
import { getEntityConnectionByEntityId, getWorkspaceConnectionById } from "@/db/query/connection";
|
||||
import { GitlabConnectionDetails, GitlabEntityConnection } from "../types";
|
||||
import { getAllEntityConnectionsByEntityIds, getEntityConnectionByEntityId, getEntityConnectionByWorkspaceConnectionAndProjectId, getWorkspaceConnectionById } from "@/db/query/connection";
|
||||
import { logger } from "@/logger";
|
||||
import { verifyEntityConnection, verifyWorkspaceConnection } from "@/types";
|
||||
import { verifyEntityConnection, verifyEntityConnections, verifyWorkspaceConnection } from "@/types";
|
||||
|
||||
export const getGitlabConnectionDetails = async (
|
||||
data: GitlabMergeRequestEvent
|
||||
): Promise<GitlabConnectionDetails | undefined> => {
|
||||
const entityConnectionSet = await getEntityConnectionByEntityId(data.project.id.toString());
|
||||
// for connection now user can also just have a group connection
|
||||
// project payload has array of groups attached to it so we need to check
|
||||
// if we have any group connections among them and use that or not then check for project connection
|
||||
|
||||
const projectRelatedGroups = data.project.shared_with_groups.map((group) => group.group_id?.toString());
|
||||
const entityConnectionIds = projectRelatedGroups.concat(data.project.id.toString());
|
||||
const entityConnectionSet = await getAllEntityConnectionsByEntityIds(entityConnectionIds);
|
||||
|
||||
if (!entityConnectionSet || entityConnectionSet.length === 0) {
|
||||
logger.error(`[GITLAB] Entity connection not found for project ${data.project.id}, skipping...`);
|
||||
logger.error(`[GITLAB] Entity connection not found for project ${entityConnectionIds}, skipping...`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -30,6 +38,15 @@ export const getGitlabConnectionDetails = async (
|
||||
|
||||
const workspaceConnection = workspaceConnectionSet[0];
|
||||
|
||||
// project connections for this workspace connection for target state mapping
|
||||
let projectConnectionSet = await getEntityConnectionByWorkspaceConnectionAndProjectId(workspaceConnection.id);
|
||||
projectConnectionSet = projectConnectionSet.filter((connection) => connection.connectionType === EConnectionType.PLANE_PROJECT);
|
||||
|
||||
if (projectConnectionSet.length === 0) {
|
||||
logger.error(`[GITLAB] Plane Project connection not found for project ${data.project.id}, skipping...`);
|
||||
return;
|
||||
}
|
||||
|
||||
const verifiedWorkspaceConnection = verifyWorkspaceConnection(
|
||||
gitlabWorkspaceConnectionSchema,
|
||||
workspaceConnection as any
|
||||
@@ -37,8 +54,11 @@ export const getGitlabConnectionDetails = async (
|
||||
|
||||
const verifiedEntityConnection = verifyEntityConnection(gitlabEntityConnectionSchema, entityConnection as any);
|
||||
|
||||
const verifiedProjectConnection = verifyEntityConnections(gitlabEntityConnectionSchema, projectConnectionSet as any);
|
||||
|
||||
return {
|
||||
workspaceConnection: verifiedWorkspaceConnection,
|
||||
entityConnection: verifiedEntityConnection,
|
||||
projectConnections: verifiedProjectConnection,
|
||||
};
|
||||
};
|
||||
|
||||
8
silo/src/apps/gitlab/services/auth.ts
Normal file
8
silo/src/apps/gitlab/services/auth.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { env } from "@/env";
|
||||
import { createGitLabAuth } from "@plane/etl/gitlab";
|
||||
|
||||
export const gitlabAuthService = createGitLabAuth({
|
||||
clientId: env.GITLAB_CLIENT_ID,
|
||||
clientSecret: env.GITLAB_CLIENT_SECRET,
|
||||
redirectUri: `${env.SILO_API_BASE_URL}/silo/api/gitlab/auth/callback`,
|
||||
});
|
||||
2
silo/src/apps/gitlab/services/index.ts
Normal file
2
silo/src/apps/gitlab/services/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./auth";
|
||||
export * from "./service"
|
||||
32
silo/src/apps/gitlab/services/service.ts
Normal file
32
silo/src/apps/gitlab/services/service.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { createOrUpdateCredentials, getCredentialsByOnlyWorkspaceId, getCredentialsByWorkspaceId } from "@/db/query";
|
||||
import { createGitLabService } from "@plane/etl/gitlab";
|
||||
|
||||
export const getGitlabClientService = async (workspaceId: string, ) => {
|
||||
try {
|
||||
// Create or update credentials
|
||||
const credentials = await getCredentialsByOnlyWorkspaceId(workspaceId, "GITLAB",);
|
||||
const { source_access_token, source_refresh_token, target_access_token, user_id: userId } = credentials[0];
|
||||
|
||||
if (!source_access_token || !source_refresh_token || !userId || !target_access_token) {
|
||||
throw new Error("No gitlab credentials available for the given workspaceId and userId");
|
||||
}
|
||||
|
||||
const gitlabService = createGitLabService(
|
||||
source_access_token,
|
||||
source_refresh_token,
|
||||
async (access_token, refresh_token) => {
|
||||
await createOrUpdateCredentials(workspaceId, userId, {
|
||||
source_access_token: access_token,
|
||||
source_refresh_token: refresh_token,
|
||||
target_access_token: target_access_token,
|
||||
source: "GITLAB",
|
||||
});
|
||||
}
|
||||
);
|
||||
return gitlabService;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,4 +7,5 @@ export type GitlabEntityConnection = EntityConnection<typeof gitlabEntityConnect
|
||||
export type GitlabConnectionDetails = {
|
||||
workspaceConnection: GitlabWorkspaceConnection;
|
||||
entityConnection: GitlabEntityConnection;
|
||||
projectConnections: GitlabEntityConnection[];
|
||||
};
|
||||
|
||||
@@ -122,7 +122,7 @@ export const handleMergeRequest = async (data: GitlabMergeRequestEvent) => {
|
||||
const result = await getConnectionAndCredentials(data);
|
||||
if (!result) return;
|
||||
|
||||
const [{ workspaceConnection, entityConnection }, credentials] = result;
|
||||
const [{ workspaceConnection, entityConnection, projectConnections }, credentials] = result;
|
||||
|
||||
const { closingReferences, nonClosingReferences } = getReferredIssues(
|
||||
data.object_attributes.title,
|
||||
@@ -133,9 +133,6 @@ export const handleMergeRequest = async (data: GitlabMergeRequestEvent) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const targetState = getTargetState(data, entityConnection);
|
||||
if (!targetState) return;
|
||||
|
||||
const referredIssues = ["MR_CLOSED", "MR_MERGED"].includes(classifyMergeRequestEvent(data))
|
||||
? closingReferences
|
||||
: [...closingReferences, ...nonClosingReferences];
|
||||
@@ -162,10 +159,31 @@ export const handleMergeRequest = async (data: GitlabMergeRequestEvent) => {
|
||||
workspaceConnection.sourceHostname!
|
||||
);
|
||||
|
||||
// we need to get the plane project attached to referred issues and then get target state for each and then do the updates
|
||||
// get the exissues from identifiers it'll have the project attached
|
||||
// loop through the referred issues, check if it has a plane project attached and then update the state using project connection target state
|
||||
|
||||
const allReferredIssues = await Promise.all(
|
||||
referredIssues.map(async (reference) => {
|
||||
const issue = await planeClient.issue.getIssueByIdentifier(
|
||||
entityConnection.workspaceSlug,
|
||||
reference.identifier,
|
||||
reference.sequence
|
||||
);
|
||||
return { reference, issue };
|
||||
})
|
||||
);
|
||||
|
||||
const updatedIssues = await Promise.all(
|
||||
referredIssues.map((reference) =>
|
||||
updateIssue(planeClient, entityConnection, reference, targetState, data.project.id)
|
||||
)
|
||||
allReferredIssues.map(async (referredIssue) => {
|
||||
const targetProject = projectConnections.find((project) => project.projectId === referredIssue.issue.project);
|
||||
if (targetProject) {
|
||||
const targetState = getTargetState(data, targetProject);
|
||||
if (!targetState) return null;
|
||||
return updateIssue(planeClient, entityConnection, referredIssue.reference, targetState, data.project.id);
|
||||
}
|
||||
return null;
|
||||
})
|
||||
);
|
||||
|
||||
const validIssues = updatedIssues.filter((issue): issue is IssueWithReference => issue !== null);
|
||||
|
||||
@@ -32,13 +32,13 @@ export const handleMessageEvent = async (data: SlackEventPayload) => {
|
||||
|
||||
const eConnection = entityConnection[0];
|
||||
|
||||
const members = await planeClient.users.list(workspaceConnection.workspaceSlug, eConnection.projectId);
|
||||
const members = await planeClient.users.list(workspaceConnection.workspaceSlug, eConnection.projectId ?? "");
|
||||
const userInfo = await slackService.getUserInfo(data.event.user);
|
||||
const issueId = eConnection.entitySlug;
|
||||
|
||||
const planeUser = members.find((member) => member.email === userInfo?.user.profile.email);
|
||||
|
||||
await planeClient.issueComment.create(workspaceConnection.workspaceSlug, eConnection.projectId, issueId, {
|
||||
await planeClient.issueComment.create(workspaceConnection.workspaceSlug, eConnection.projectId ?? "", issueId ?? "", {
|
||||
comment_html: `<p>${data.event.text}</p>`,
|
||||
external_source: "SLACK_COMMENT",
|
||||
external_id: data.event.event_ts,
|
||||
|
||||
@@ -26,12 +26,12 @@ const handleCommentSync = async (payload: WebhookIssueCommentPayload) => {
|
||||
if (credentials && credentials.length > 0 && credentials[0].source_access_token) {
|
||||
await slackService.sendMessageAsUser(
|
||||
slackData.channel,
|
||||
entityConnection[0].entityId,
|
||||
entityConnection[0].entityId ?? "",
|
||||
data.data.comment_stripped,
|
||||
credentials[0].source_access_token
|
||||
);
|
||||
} else {
|
||||
await slackService.sendThreadMessage(slackData.channel, entityConnection[0].entityId, data.data.comment_stripped);
|
||||
await slackService.sendThreadMessage(slackData.channel, entityConnection[0].entityId ?? "", data.data.comment_stripped);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
4
silo/src/db/migrations/0003_typical_eternity.sql
Normal file
4
silo/src/db/migrations/0003_typical_eternity.sql
Normal file
@@ -0,0 +1,4 @@
|
||||
ALTER TABLE "silo"."entity_connections" ALTER COLUMN "entity_id" DROP NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "silo"."entity_connections" ALTER COLUMN "entity_slug" DROP NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "silo"."entity_connections" ALTER COLUMN "project_id" DROP NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "silo"."entity_connections" ADD COLUMN "connection_type" varchar(50) DEFAULT 'ENTITY';
|
||||
537
silo/src/db/migrations/meta/0003_snapshot.json
Normal file
537
silo/src/db/migrations/meta/0003_snapshot.json
Normal file
@@ -0,0 +1,537 @@
|
||||
{
|
||||
"id": "8db1d4b5-7542-4785-85fe-ddfa487cdc87",
|
||||
"prevId": "1bb1de16-c54b-43a3-874e-dc5d0a9ced7c",
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"tables": {
|
||||
"silo.entity_connections": {
|
||||
"name": "entity_connections",
|
||||
"schema": "silo",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"connection_type": {
|
||||
"name": "connection_type",
|
||||
"type": "varchar(50)",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "'ENTITY'"
|
||||
},
|
||||
"entity_id": {
|
||||
"name": "entity_id",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"entity_slug": {
|
||||
"name": "entity_slug",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"entity_data": {
|
||||
"name": "entity_data",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "'{}'::jsonb"
|
||||
},
|
||||
"project_id": {
|
||||
"name": "project_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"workspace_id": {
|
||||
"name": "workspace_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"workspace_slug": {
|
||||
"name": "workspace_slug",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"workspace_connection_id": {
|
||||
"name": "workspace_connection_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"config": {
|
||||
"name": "config",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "'{}'::jsonb"
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"entity_connections_workspace_id_idx": {
|
||||
"name": "entity_connections_workspace_id_idx",
|
||||
"columns": [
|
||||
{
|
||||
"expression": "workspace_id",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last"
|
||||
}
|
||||
],
|
||||
"isUnique": false,
|
||||
"concurrently": false,
|
||||
"method": "btree",
|
||||
"with": {}
|
||||
}
|
||||
},
|
||||
"foreignKeys": {
|
||||
"entity_connections_workspace_connection_id_workspace_connections_id_fk": {
|
||||
"name": "entity_connections_workspace_connection_id_workspace_connections_id_fk",
|
||||
"tableFrom": "entity_connections",
|
||||
"tableTo": "workspace_connections",
|
||||
"schemaTo": "silo",
|
||||
"columnsFrom": [
|
||||
"workspace_connection_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"silo.workspace_connections": {
|
||||
"name": "workspace_connections",
|
||||
"schema": "silo",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"workspace_id": {
|
||||
"name": "workspace_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"workspace_slug": {
|
||||
"name": "workspace_slug",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"target_hostname": {
|
||||
"name": "target_hostname",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"source_hostname": {
|
||||
"name": "source_hostname",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"connection_type": {
|
||||
"name": "connection_type",
|
||||
"type": "varchar(50)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"connection_slug": {
|
||||
"name": "connection_slug",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"connection_id": {
|
||||
"name": "connection_id",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"connection_data": {
|
||||
"name": "connection_data",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "'{}'::jsonb"
|
||||
},
|
||||
"credentials_id": {
|
||||
"name": "credentials_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"config": {
|
||||
"name": "config",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "'{}'::jsonb"
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"workspace_connections_workspace_id_idx": {
|
||||
"name": "workspace_connections_workspace_id_idx",
|
||||
"columns": [
|
||||
{
|
||||
"expression": "workspace_id",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last"
|
||||
}
|
||||
],
|
||||
"isUnique": false,
|
||||
"concurrently": false,
|
||||
"method": "btree",
|
||||
"with": {}
|
||||
}
|
||||
},
|
||||
"foreignKeys": {
|
||||
"workspace_connections_credentials_id_credentials_id_fk": {
|
||||
"name": "workspace_connections_credentials_id_credentials_id_fk",
|
||||
"tableFrom": "workspace_connections",
|
||||
"tableTo": "credentials",
|
||||
"schemaTo": "silo",
|
||||
"columnsFrom": [
|
||||
"credentials_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"silo.credentials": {
|
||||
"name": "credentials",
|
||||
"schema": "silo",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"source": {
|
||||
"name": "source",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"workspace_id": {
|
||||
"name": "workspace_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"user_email": {
|
||||
"name": "user_email",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"source_access_token": {
|
||||
"name": "source_access_token",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"source_refresh_token": {
|
||||
"name": "source_refresh_token",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"source_hostname": {
|
||||
"name": "source_hostname",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"target_access_token": {
|
||||
"name": "target_access_token",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"is_pat": {
|
||||
"name": "is_pat",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": false
|
||||
},
|
||||
"is_active": {
|
||||
"name": "is_active",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": true
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"workspace_id_idx": {
|
||||
"name": "workspace_id_idx",
|
||||
"columns": [
|
||||
{
|
||||
"expression": "workspace_id",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last"
|
||||
}
|
||||
],
|
||||
"isUnique": false,
|
||||
"concurrently": false,
|
||||
"method": "btree",
|
||||
"with": {}
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"silo.job_configs": {
|
||||
"name": "job_configs",
|
||||
"schema": "silo",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"meta": {
|
||||
"name": "meta",
|
||||
"type": "json",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "'{}'::json"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"silo.jobs": {
|
||||
"name": "jobs",
|
||||
"schema": "silo",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"config_id": {
|
||||
"name": "config_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"migration_type": {
|
||||
"name": "migration_type",
|
||||
"type": "varchar",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"project_id": {
|
||||
"name": "project_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"workspace_id": {
|
||||
"name": "workspace_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"workspace_slug": {
|
||||
"name": "workspace_slug",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"initiator_id": {
|
||||
"name": "initiator_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"initiator_email": {
|
||||
"name": "initiator_email",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"completed_batch_count": {
|
||||
"name": "completed_batch_count",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": 0
|
||||
},
|
||||
"transformed_batch_count": {
|
||||
"name": "transformed_batch_count",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": 0
|
||||
},
|
||||
"total_batch_count": {
|
||||
"name": "total_batch_count",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": 0
|
||||
},
|
||||
"start_time": {
|
||||
"name": "start_time",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"end_time": {
|
||||
"name": "end_time",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "varchar",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "'CREATED'"
|
||||
},
|
||||
"is_cancelled": {
|
||||
"name": "is_cancelled",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "now()"
|
||||
},
|
||||
"error": {
|
||||
"name": "error",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "''"
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"project_idx": {
|
||||
"name": "project_idx",
|
||||
"columns": [
|
||||
{
|
||||
"expression": "project_id",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last"
|
||||
}
|
||||
],
|
||||
"isUnique": false,
|
||||
"concurrently": false,
|
||||
"method": "btree",
|
||||
"with": {}
|
||||
}
|
||||
},
|
||||
"foreignKeys": {
|
||||
"jobs_config_id_job_configs_id_fk": {
|
||||
"name": "jobs_config_id_job_configs_id_fk",
|
||||
"tableFrom": "jobs",
|
||||
"tableTo": "job_configs",
|
||||
"schemaTo": "silo",
|
||||
"columnsFrom": [
|
||||
"config_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
}
|
||||
},
|
||||
"enums": {},
|
||||
"schemas": {
|
||||
"silo": "silo"
|
||||
},
|
||||
"_meta": {
|
||||
"columns": {},
|
||||
"schemas": {},
|
||||
"tables": {}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,13 @@
|
||||
"when": 1734517027583,
|
||||
"tag": "0002_lazy_spyke",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 3,
|
||||
"version": "7",
|
||||
"when": 1735053738861,
|
||||
"tag": "0003_typical_eternity",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { SQL, and, eq } from "drizzle-orm";
|
||||
import { SQL, and, eq, inArray } from "drizzle-orm";
|
||||
import { db } from "../config/db.config";
|
||||
import { entityConnections, workspaceConnections } from "../schema/connection.schema";
|
||||
|
||||
@@ -62,6 +62,13 @@ export async function createEntityConnection(data: typeof entityConnections.$inf
|
||||
return await db.insert(entityConnections).values(data).returning();
|
||||
}
|
||||
|
||||
export async function getAllEntityConnectionsByEntityIds(entityIds: string[]) {
|
||||
return await db
|
||||
.select()
|
||||
.from(entityConnections)
|
||||
.where(inArray(entityConnections.entityId, entityIds));
|
||||
}
|
||||
|
||||
export async function getEntityConnectionByWorkspaceId(workspaceId: string) {
|
||||
return await db.select().from(entityConnections).where(eq(entityConnections.workspaceId, workspaceId));
|
||||
}
|
||||
@@ -87,6 +94,19 @@ export async function getEntityConnectionByWorkspaceAndProjectId(workspaceId: st
|
||||
.where(and(...conditions));
|
||||
}
|
||||
|
||||
export async function getEntityConnectionByWorkspaceConnectionAndProjectId(workspaceConnectionId: string, projectId?: string) {
|
||||
const conditions: SQL[] = [eq(entityConnections.workspaceConnectionId, workspaceConnectionId)];
|
||||
|
||||
if (projectId) {
|
||||
conditions.push(eq(entityConnections.projectId, projectId));
|
||||
}
|
||||
|
||||
return await db
|
||||
.select()
|
||||
.from(entityConnections)
|
||||
.where(and(...conditions));
|
||||
}
|
||||
|
||||
export async function getEntityConnectionByEntitySlug(workspaceId: string, projectId: string, entitySlug: string) {
|
||||
return await db
|
||||
.select()
|
||||
@@ -134,16 +154,21 @@ export async function deleteEntityConnectionByWorkspaceConnectionId(workspaceCon
|
||||
// Get entity connection by workspaceId, and workspaceConnectionId
|
||||
export async function getEntityConnectionByWorkspaceIdAndConnectionId(
|
||||
workspaceId: string,
|
||||
workspaceConnectionId: string
|
||||
workspaceConnectionId: string,
|
||||
connectionType?: string
|
||||
) {
|
||||
const conditions: SQL[] = [eq(entityConnections.workspaceId, workspaceId),
|
||||
eq(entityConnections.workspaceConnectionId, workspaceConnectionId)];
|
||||
|
||||
if (connectionType) {
|
||||
conditions.push(eq(entityConnections.connectionType, connectionType));
|
||||
}
|
||||
|
||||
return await db
|
||||
.select()
|
||||
.from(entityConnections)
|
||||
.where(
|
||||
and(
|
||||
eq(entityConnections.workspaceId, workspaceId),
|
||||
eq(entityConnections.workspaceConnectionId, workspaceConnectionId)
|
||||
)
|
||||
and(...conditions)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,13 +51,16 @@ export const entityConnections = schema.table(
|
||||
{
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
|
||||
// connection type can be a plane project connection or a secondary entity connection or a mapping in both
|
||||
connectionType: varchar("connection_type", { length: 50 }).default("ENTITY"),
|
||||
|
||||
// Entity Type can be a github repository, and entity id can be the repository id
|
||||
entityId: varchar("entity_id", { length: 255 }).notNull(),
|
||||
entitySlug: varchar("entity_slug", { length: 255 }).notNull(),
|
||||
entityId: varchar("entity_id", { length: 255 }),
|
||||
entitySlug: varchar("entity_slug", { length: 255 }),
|
||||
entityData: jsonb("entity_data").default({}),
|
||||
|
||||
// Project and WorkspaceId of Plane
|
||||
projectId: uuid("project_id").notNull(),
|
||||
projectId: uuid("project_id"),
|
||||
workspaceId: uuid("workspace_id").notNull(),
|
||||
workspaceSlug: varchar("workspace_slug", { length: 255 }).notNull(),
|
||||
|
||||
|
||||
@@ -40,6 +40,18 @@ export function verifyEntityConnection<T extends z.ZodType>(schema: T, data: Ent
|
||||
const parsedConfig = schema.parse(data.config);
|
||||
return { ...data, config: parsedConfig };
|
||||
}
|
||||
|
||||
export function verifyEntityConnections<T extends z.ZodType>(
|
||||
schema: T,
|
||||
dataArray: EntityConnection<T>[]
|
||||
): EntityConnection<T>[] {
|
||||
return dataArray.map((data) => {
|
||||
const parsedConfig = schema.parse(data.config);
|
||||
return { ...data, config: parsedConfig };
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export type Credentials = typeof credentials.$inferInsert;
|
||||
|
||||
export type BulkIssuePayload = ExIssue & {
|
||||
@@ -52,3 +64,10 @@ export type BulkIssuePayload = ExIssue & {
|
||||
values: ExIssuePropertyValue;
|
||||
}[];
|
||||
};
|
||||
|
||||
|
||||
export enum EIntegrationType {
|
||||
GITLAB = "GITLAB",
|
||||
GITHUB = "GITHUB",
|
||||
SLACK = "SLACK",
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ export function PersonalAccountConnectView(props: TPersonalAccountConnectProps)
|
||||
return (
|
||||
<div className="flex flex-col border border-custom-border-200 rounded-s p-4 mb-2 justify-center">
|
||||
<div className="flex items-center gap-2">
|
||||
<provider.icon className="w-8 h-8" />
|
||||
{provider.icon && <provider.icon className="w-8 h-8" />}
|
||||
<div className="text-lg font-medium">{provider.name}</div>
|
||||
</div>
|
||||
<div className="text-sm text-gray-500 pt-2 pb-4">{provider.description}</div>
|
||||
|
||||
@@ -36,7 +36,13 @@ export const UserConnectionsView = observer(({ workspaceId }: { workspaceId: str
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedWorkspace && !isLoading) {
|
||||
const response = getConnectionsByWorkspaceSlug(selectedWorkspace.slug);
|
||||
let response = getConnectionsByWorkspaceSlug(selectedWorkspace.slug);
|
||||
response = (response || []).reduce((allConnections: any, connection: any) => {
|
||||
if (connection.connectionType !== "GITLAB") {
|
||||
allConnections.push(connection);
|
||||
}
|
||||
return allConnections;
|
||||
}, []);
|
||||
setConnections(response);
|
||||
}
|
||||
|
||||
|
||||
@@ -79,13 +79,10 @@ export const ConnectOrganization: FC = observer(() => {
|
||||
<img
|
||||
src={workspaceConnection?.connectionData?.avatar_url}
|
||||
alt={workspaceConnection?.connectionData?.login}
|
||||
className="object-contain w-full h-full overflow-hidden"
|
||||
className="object-contain w-10 h-10 overflow-hidden rounded"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-0.5 w-full">
|
||||
<div className="text-base font-medium">{workspaceConnection?.connectionData?.login}</div>
|
||||
<div className="text-sm text-custom-text-200">Gitlab org added by and time</div>
|
||||
</div>
|
||||
<div className="text-sm text-custom-text-200 font-medium">{workspaceConnection?.connectionData?.organization || workspaceConnection?.connectionData?.name}</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-0.5 w-full">
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import { FC, useState } from "react";
|
||||
import { Component, FC, ReactElement, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import Image from "next/image";
|
||||
import { IProject } from "@plane/types";
|
||||
import { Button, ModalCore } from "@plane/ui";
|
||||
// plane web components
|
||||
import { Button, ModalCore } from "@plane/ui";
|
||||
import { Logo } from "@/components/common";
|
||||
import { FormEdit } from "@/plane-web/components/integrations/gitlab";
|
||||
// plane web hooks
|
||||
import { useGitlabIntegration } from "@/plane-web/hooks/store";
|
||||
@@ -13,19 +13,20 @@ import { useGitlabIntegration } from "@/plane-web/hooks/store";
|
||||
import { TGitlabEntityConnection } from "@/plane-web/types/integrations/gitlab";
|
||||
// public images
|
||||
import GitlabLogo from "@/public/services/gitlab.svg";
|
||||
import { EConnectionType } from "@plane/etl/gitlab";
|
||||
|
||||
type TEntityConnectionItem = {
|
||||
project: IProject;
|
||||
entityConnection: TGitlabEntityConnection;
|
||||
};
|
||||
|
||||
export const EntityConnectionItem: FC<TEntityConnectionItem> = observer((props) => {
|
||||
// props
|
||||
const { project, entityConnection } = props;
|
||||
const { entityConnection } = props;
|
||||
|
||||
// hooks
|
||||
const {
|
||||
entity: { deleteEntity },
|
||||
getProjectById,
|
||||
entityConnection: { deleteEntityConnection },
|
||||
} = useGitlabIntegration();
|
||||
|
||||
// states
|
||||
@@ -43,7 +44,7 @@ export const EntityConnectionItem: FC<TEntityConnectionItem> = observer((props)
|
||||
const handleDeleteModalSubmit = async () => {
|
||||
try {
|
||||
setDeleteLoader(true);
|
||||
await deleteEntity(entityConnection.id);
|
||||
await deleteEntityConnection(entityConnection.id);
|
||||
setDeleteModal(false);
|
||||
} catch (error) {
|
||||
console.error("handleDeleteModalSubmit", error);
|
||||
@@ -52,16 +53,35 @@ export const EntityConnectionItem: FC<TEntityConnectionItem> = observer((props)
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* entity edit */}
|
||||
const getEntityName = (entityconnection: TGitlabEntityConnection): string => {
|
||||
if (entityconnection.connectionType === EConnectionType.PLANE_PROJECT) {
|
||||
return getProjectById(entityconnection.projectId)?.name || "";
|
||||
} else if (entityconnection.connectionType === EConnectionType.ENTITY) {
|
||||
return entityconnection.entitySlug;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
const getEntityLogo = (entityconnection: TGitlabEntityConnection): ReactElement => {
|
||||
if (entityconnection.connectionType === EConnectionType.PLANE_PROJECT) {
|
||||
const project = getProjectById(entityconnection.projectId);
|
||||
if (!project) return <></>;
|
||||
return <Logo logo={project.logo_props} size={14} />;
|
||||
} else if (entityconnection.connectionType === EConnectionType.ENTITY) {
|
||||
return <Image src={GitlabLogo} layout="fill" objectFit="contain" alt="Gitlab Logo" />;
|
||||
}
|
||||
return <></>;
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
<>
|
||||
{/* entity delete */}
|
||||
<ModalCore isOpen={deleteModal} handleClose={handleDeleteClose}>
|
||||
<div className="space-y-5 p-5">
|
||||
<div className="space-y-2">
|
||||
<div className="text-xl font-medium text-custom-text-200">Remove entity</div>
|
||||
<div className="text-sm text-custom-text-300">Are you sure you want to remove this entity?</div>
|
||||
<div className="text-xl font-medium text-custom-text-200">Remove Connection</div>
|
||||
<div className="text-sm text-custom-text-300">Are you sure you want to remove this connection?</div>
|
||||
</div>
|
||||
<div className="relative flex justify-end items-center gap-2">
|
||||
<Button variant="neutral-primary" size="sm" onClick={handleDeleteClose} disabled={deleteLoader}>
|
||||
@@ -80,24 +100,24 @@ export const EntityConnectionItem: FC<TEntityConnectionItem> = observer((props)
|
||||
</div>
|
||||
</ModalCore>
|
||||
|
||||
{/* entity edit */}
|
||||
<FormEdit modal={editModal} handleModal={setEditModal} data={entityConnection} />
|
||||
|
||||
<div className="relative flex items-center gap-2 p-2 bg-custom-background-90/20">
|
||||
<div className="flex-shrink-0 relative flex justify-center items-center w-8 h-8 rounded">
|
||||
<Image src={GitlabLogo} layout="fill" objectFit="contain" alt="Gitlab Logo" />
|
||||
{getEntityLogo(entityConnection)}
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<div className="text-sm font-medium">
|
||||
{entityConnection?.entityData?.name} ({entityConnection?.entityData?.full_name})
|
||||
</div>
|
||||
<div className="text-xs text-custom-text-200">
|
||||
Issues are synced to <b>{project?.name || "Project"}</b>
|
||||
{getEntityName(entityConnection)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative flex items-center gap-2">
|
||||
<Button variant="neutral-primary" size="sm" onClick={handleEditOpen}>
|
||||
Edit
|
||||
</Button>
|
||||
{entityConnection.connectionType === EConnectionType.PLANE_PROJECT && (
|
||||
<Button variant="neutral-primary" size="sm" onClick={handleEditOpen}>
|
||||
Edit
|
||||
</Button>
|
||||
)}
|
||||
<Button variant="link-danger" size="sm" onClick={handleDeleteOpen}>
|
||||
Remove
|
||||
</Button>
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
"use client";
|
||||
|
||||
import { Dispatch, FC, SetStateAction, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Button, ModalCore } from "@plane/ui";
|
||||
// plane web components
|
||||
import { EntityForm } from "@/plane-web/components/integrations/gitlab";
|
||||
// plane web hooks
|
||||
import { useGitlabIntegration } from "@/plane-web/hooks/store";
|
||||
// plane web types
|
||||
import { TGitlabEntityConnection, TProjectMap } from "@/plane-web/types/integrations/gitlab";
|
||||
// local imports
|
||||
import { projectMapInit } from "../root";
|
||||
|
||||
type TEntityFormCreate = {
|
||||
modal: boolean;
|
||||
handleModal: Dispatch<SetStateAction<boolean>>;
|
||||
};
|
||||
|
||||
export const EntityFormCreate: FC<TEntityFormCreate> = observer((props) => {
|
||||
// props
|
||||
const { modal, handleModal } = props;
|
||||
|
||||
// hooks
|
||||
const {
|
||||
entityConnection: { createEntityConnection },
|
||||
} = useGitlabIntegration();
|
||||
|
||||
// states
|
||||
const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
|
||||
const [projectMap, setProjectMap] = useState<TProjectMap>(projectMapInit);
|
||||
|
||||
// handlers
|
||||
const handleProjectMapChange = <T extends keyof TProjectMap>(key: T, value: TProjectMap[T]) => {
|
||||
setProjectMap((prev) => ({ ...prev, [key]: value }));
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
setIsSubmitting(true);
|
||||
const payload: Partial<TGitlabEntityConnection> = {
|
||||
entityId: projectMap.entityId,
|
||||
projectId: projectMap.projectId,
|
||||
};
|
||||
await createEntityConnection(payload);
|
||||
|
||||
handleModal(false);
|
||||
} catch (error) {
|
||||
console.error("handleSubmit", error);
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ModalCore isOpen={modal} handleClose={() => handleModal(false)}>
|
||||
<div className="space-y-5 p-5">
|
||||
<div className="text-xl font-medium text-custom-text-200">Link Gitlab Project or Group</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<EntityForm value={projectMap} handleChange={handleProjectMapChange} />
|
||||
|
||||
<div className="border border-custom-border-200 divide-y divide-custom-border-200 rounded">
|
||||
<div className="relative space-y-1 p-3">
|
||||
<div className="text-base">Pull request automation</div>
|
||||
<div className="text-xs text-custom-text-200">
|
||||
With Gitlab integration Enabled, you can automate issue workflows
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="relative flex justify-end items-center gap-2">
|
||||
<Button variant="neutral-primary" size="sm" onClick={() => handleModal(false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button variant="primary" size="sm" onClick={handleSubmit} loading={isSubmitting} disabled={isSubmitting}>
|
||||
{isSubmitting ? "Processing" : "Continue"}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ModalCore>
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,117 @@
|
||||
"use client";
|
||||
|
||||
import { Dispatch, FC, SetStateAction, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Button, ModalCore } from "@plane/ui";
|
||||
// plane web components
|
||||
import { ProjectForm, StateForm } from "@/plane-web/components/integrations/gitlab";
|
||||
// plane web hooks
|
||||
import { useGitlabIntegration } from "@/plane-web/hooks/store";
|
||||
// plane web types
|
||||
import { TGitlabEntityConnection, TProjectMap, TStateMap } from "@/plane-web/types/integrations/gitlab";
|
||||
// local imports
|
||||
import { projectMapInit, stateMapInit } from "../root";
|
||||
|
||||
type TProjectEntityFormCreate = {
|
||||
modal: boolean;
|
||||
handleModal: Dispatch<SetStateAction<boolean>>;
|
||||
};
|
||||
|
||||
export const ProjectEntityFormCreate: FC<TProjectEntityFormCreate> = observer((props) => {
|
||||
// props
|
||||
const { modal, handleModal } = props;
|
||||
|
||||
// hooks
|
||||
const {
|
||||
workspace,
|
||||
fetchStates,
|
||||
entityConnection: { createProjectConnection },
|
||||
} = useGitlabIntegration();
|
||||
|
||||
// states
|
||||
const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
|
||||
const [projectMap, setProjectMap] = useState<TProjectMap>(projectMapInit);
|
||||
const [stateMap, setStateMap] = useState<TStateMap>(stateMapInit);
|
||||
|
||||
// derived values
|
||||
const workspaceSlug = workspace?.slug || undefined;
|
||||
|
||||
// handlers
|
||||
const handleProjectMapChange = <T extends keyof TProjectMap>(key: T, value: TProjectMap[T]) => {
|
||||
if (key === "projectId") {
|
||||
setProjectMap((prev) => ({ ...prev, [key]: value }));
|
||||
if (workspaceSlug && value && value != projectMap.projectId) {
|
||||
fetchStates(workspaceSlug, value);
|
||||
setStateMap(stateMapInit);
|
||||
}
|
||||
} else {
|
||||
setProjectMap((prev) => ({ ...prev, [key]: value }));
|
||||
}
|
||||
};
|
||||
|
||||
const handleStateMapChange = <T extends keyof TStateMap>(key: T, value: (typeof stateMap)[T]) => {
|
||||
setStateMap((prev) => ({ ...prev, [key]: value }));
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
setIsSubmitting(true);
|
||||
|
||||
const payload: Partial<TGitlabEntityConnection> = {
|
||||
entityId: projectMap.entityId,
|
||||
projectId: projectMap.projectId,
|
||||
config: {
|
||||
states: { mergeRequestEventMapping: stateMap },
|
||||
},
|
||||
};
|
||||
await createProjectConnection(payload);
|
||||
|
||||
handleModal(false);
|
||||
} catch (error) {
|
||||
console.error("handleSubmit", error);
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ModalCore isOpen={modal} handleClose={() => handleModal(false)}>
|
||||
<div className="space-y-5 p-5">
|
||||
<div className="text-xl font-medium text-custom-text-200">Link Gitlab repository and Plane project</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<ProjectForm value={projectMap} handleChange={handleProjectMapChange} />
|
||||
|
||||
<div className="border border-custom-border-200 divide-y divide-custom-border-200 rounded">
|
||||
<div className="relative space-y-1 p-3">
|
||||
<div className="text-base">Pull request automation</div>
|
||||
<div className="text-xs text-custom-text-200">
|
||||
Configure pull request state mapping from Gitlab to Plane
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
projectMap.projectId && (
|
||||
<div className="p-3">
|
||||
<StateForm
|
||||
projectId={projectMap.projectId}
|
||||
value={stateMap}
|
||||
handleChange={handleStateMapChange}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className="relative flex justify-end items-center gap-2">
|
||||
<Button variant="neutral-primary" size="sm" onClick={() => handleModal(false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button variant="primary" size="sm" onClick={handleSubmit} loading={isSubmitting} disabled={isSubmitting}>
|
||||
{isSubmitting ? "Processing" : "Continue"}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ModalCore>
|
||||
);
|
||||
});
|
||||
@@ -4,18 +4,19 @@ import { Dispatch, FC, SetStateAction, useEffect, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Button, ModalCore } from "@plane/ui";
|
||||
// plane web components
|
||||
import { ProjectForm, StateForm } from "@/plane-web/components/integrations/github";
|
||||
import { ProjectForm, StateForm } from "@/plane-web/components/integrations/gitlab";
|
||||
// plane web hooks
|
||||
import { useGithubIntegration } from "@/plane-web/hooks/store";
|
||||
import { useGitlabIntegration } from "@/plane-web/hooks/store";
|
||||
// plane web types
|
||||
import { E_STATE_MAP_KEYS, TGithubEntityConnection, TProjectMap, TStateMap } from "@/plane-web/types/integrations";
|
||||
import { E_STATE_MAP_KEYS, TProjectMap, TStateMap } from "@/plane-web/types/integrations";
|
||||
// local imports
|
||||
import { projectMapInit, stateMapInit } from "../root";
|
||||
import { TGitlabEntityConnection } from "@/plane-web/types/integrations/gitlab";
|
||||
|
||||
type TFormEdit = {
|
||||
modal: boolean;
|
||||
handleModal: Dispatch<SetStateAction<boolean>>;
|
||||
data: TGithubEntityConnection;
|
||||
data: TGitlabEntityConnection;
|
||||
};
|
||||
|
||||
export const FormEdit: FC<TFormEdit> = observer((props) => {
|
||||
@@ -26,8 +27,8 @@ export const FormEdit: FC<TFormEdit> = observer((props) => {
|
||||
const {
|
||||
workspace,
|
||||
fetchStates,
|
||||
entity: { updateEntity },
|
||||
} = useGithubIntegration();
|
||||
entityConnection: { updateEntityConnection },
|
||||
} = useGitlabIntegration();
|
||||
|
||||
// states
|
||||
const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
|
||||
@@ -58,14 +59,13 @@ export const FormEdit: FC<TFormEdit> = observer((props) => {
|
||||
try {
|
||||
setIsSubmitting(true);
|
||||
|
||||
const payload: Partial<TGithubEntityConnection> = {
|
||||
entityId: projectMap.entityId,
|
||||
const payload: Partial<TGitlabEntityConnection> = {
|
||||
projectId: projectMap.projectId,
|
||||
config: {
|
||||
states: { mergeRequestEventMapping: stateMap },
|
||||
},
|
||||
};
|
||||
await updateEntity(data.id, payload);
|
||||
await updateEntityConnection(data.id, payload);
|
||||
|
||||
handleModal(false);
|
||||
} catch (error) {
|
||||
@@ -112,7 +112,7 @@ export const FormEdit: FC<TFormEdit> = observer((props) => {
|
||||
<div className="relative space-y-1 p-3">
|
||||
<div className="text-base">Pull request automation</div>
|
||||
<div className="text-xs text-custom-text-200">
|
||||
With Github integration Enabled, you can automate issue workflows
|
||||
With Gitlab integration Enabled, you can automate issue workflows
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-3">
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
"use client";
|
||||
|
||||
import { FC } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import Image from "next/image";
|
||||
import { Briefcase } from "lucide-react";
|
||||
// components
|
||||
import { Logo } from "@/components/common";
|
||||
// plane web components
|
||||
import { Dropdown } from "@/plane-web/components/importers/ui";
|
||||
// plane web hooks
|
||||
import { useGitlabIntegration } from "@/plane-web/hooks/store";
|
||||
// plane web types
|
||||
import { TProjectMap } from "@/plane-web/types/integrations";
|
||||
// public images
|
||||
import GitlabLogo from "@/public/services/gitlab.svg";
|
||||
|
||||
type TEntityForm = {
|
||||
value: TProjectMap;
|
||||
handleChange: <T extends keyof TProjectMap>(key: T, value: TProjectMap[T]) => void;
|
||||
};
|
||||
|
||||
export const EntityForm: FC<TEntityForm> = observer((props) => {
|
||||
// props
|
||||
const { value, handleChange } = props;
|
||||
// hooks
|
||||
const { data: { gitlabEntityIds, gitlabEntityById } } = useGitlabIntegration();
|
||||
|
||||
// derived values
|
||||
const entities = (gitlabEntityIds || [])
|
||||
.map((id) => {
|
||||
const entity = gitlabEntityById(id);
|
||||
return entity || undefined;
|
||||
})
|
||||
.filter((entity) => entity !== undefined && entity !== null);
|
||||
|
||||
return (
|
||||
<div className="relative space-y-4 text-sm">
|
||||
<div className="space-y-1">
|
||||
<div className="text-custom-text-200">Gitlab Project or Group</div>
|
||||
<Dropdown
|
||||
dropdownOptions={(entities || [])?.map((entity) => ({
|
||||
key: entity?.id.toString() || "",
|
||||
label: entity?.name || "",
|
||||
value: entity?.id.toString() || "",
|
||||
data: entity,
|
||||
}))}
|
||||
value={value?.entityId || undefined}
|
||||
placeHolder="Choose Entity..."
|
||||
onChange={(value: string | undefined) => handleChange("entityId", value || undefined)}
|
||||
iconExtractor={() => (
|
||||
<div className="w-4 h-4 flex-shrink-0 overflow-hidden relative flex justify-center items-center">
|
||||
<Image src={GitlabLogo} layout="fill" objectFit="contain" alt="Gitlab Logo" />
|
||||
</div>
|
||||
)}
|
||||
queryExtractor={(option) => option.name}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
@@ -1,4 +1,6 @@
|
||||
export * from "./create";
|
||||
export * from "./create-project-entity";
|
||||
export * from "./edit";
|
||||
export * from "./project-form";
|
||||
export * from "./state-form";
|
||||
export * from "./create-entity";
|
||||
export * from "./entity-form";
|
||||
|
||||
@@ -13,7 +13,6 @@ import { useGitlabIntegration } from "@/plane-web/hooks/store";
|
||||
// plane web types
|
||||
import { TProjectMap } from "@/plane-web/types/integrations";
|
||||
// public images
|
||||
import GitlabLogo from "@/public/services/gitlab.svg";
|
||||
|
||||
type TProjectForm = {
|
||||
value: TProjectMap;
|
||||
@@ -29,17 +28,9 @@ export const ProjectForm: FC<TProjectForm> = observer((props) => {
|
||||
workspace,
|
||||
projectIdsByWorkspaceSlug,
|
||||
getProjectById,
|
||||
data: { gitlabRepositoryIds, gitlabRepositoryById },
|
||||
} = useGitlabIntegration();
|
||||
|
||||
// derived values
|
||||
const repositories = (gitlabRepositoryIds || [])
|
||||
.map((id) => {
|
||||
const repository = gitlabRepositoryById(id);
|
||||
return repository || undefined;
|
||||
})
|
||||
.filter((repo) => repo !== undefined && repo !== null);
|
||||
|
||||
const workspaceSlug = workspace?.slug || undefined;
|
||||
const planeProjectIds = (workspaceSlug && projectIdsByWorkspaceSlug(workspaceSlug)) || [];
|
||||
const planeProjects = planeProjectIds
|
||||
@@ -48,27 +39,6 @@ export const ProjectForm: FC<TProjectForm> = observer((props) => {
|
||||
|
||||
return (
|
||||
<div className="relative space-y-4 text-sm">
|
||||
<div className="space-y-1">
|
||||
<div className="text-custom-text-200">Gitlab Repository</div>
|
||||
<Dropdown
|
||||
dropdownOptions={(repositories || [])?.map((repo) => ({
|
||||
key: repo?.id.toString() || "",
|
||||
label: repo?.name || "",
|
||||
value: repo?.id.toString() || "",
|
||||
data: repo,
|
||||
}))}
|
||||
value={value?.entityId || undefined}
|
||||
placeHolder="Choose Repository..."
|
||||
onChange={(value: string | undefined) => handleChange("entityId", value || undefined)}
|
||||
iconExtractor={() => (
|
||||
<div className="w-4 h-4 flex-shrink-0 overflow-hidden relative flex justify-center items-center">
|
||||
<Image src={GitlabLogo} layout="fill" objectFit="contain" alt="Gitlab Logo" />
|
||||
</div>
|
||||
)}
|
||||
queryExtractor={(option) => option.name}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
<div className="text-custom-text-200">Plane Project</div>
|
||||
<Dropdown
|
||||
|
||||
@@ -57,7 +57,7 @@ export const StateForm: FC<TStateForm> = observer((props) => {
|
||||
|
||||
return (
|
||||
<div className="w-full min-h-44 max-h-full overflow-y-auto">
|
||||
{planeProjectStates &&
|
||||
{planeProjectStates && projectId &&
|
||||
GIT_PR_DATA.map((gitState) => (
|
||||
<StateFormSelection
|
||||
title={gitState.title}
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
import { FC, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import useSWR from "swr";
|
||||
import { Briefcase } from "lucide-react";
|
||||
import { Button } from "@plane/ui";
|
||||
import { Briefcase, BriefcaseBusiness } from "lucide-react";
|
||||
import { Button, Loader } from "@plane/ui";
|
||||
// plane web components
|
||||
import { Logo } from "@/components/common";
|
||||
import { EntityConnectionItem, FormCreate } from "@/plane-web/components/integrations/gitlab";
|
||||
import { EntityConnectionItem, EntityFormCreate, ProjectEntityFormCreate } from "@/plane-web/components/integrations/gitlab";
|
||||
// plane web hooks
|
||||
import { useGitlabIntegration } from "@/plane-web/hooks/store";
|
||||
// plane web types
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
TProjectMap,
|
||||
TStateMap,
|
||||
} from "@/plane-web/types/integrations/gitlab";
|
||||
import { EConnectionType, GitlabEntityType } from "@plane/etl/gitlab";
|
||||
|
||||
export const projectMapInit: TProjectMap = {
|
||||
entityId: undefined,
|
||||
@@ -37,38 +38,40 @@ export const RepositoryMappingRoot: FC = observer(() => {
|
||||
const {
|
||||
workspace,
|
||||
fetchProjects,
|
||||
getProjectById,
|
||||
auth: { workspaceConnectionIds },
|
||||
data: { fetchGitlabRepositories },
|
||||
entity: { entityIds, entityById, fetchEntities },
|
||||
data: { fetchGitlabEntities },
|
||||
entityConnection: { entityConnectionIds, entityConnectionById, fetchEntityConnections },
|
||||
} = useGitlabIntegration();
|
||||
|
||||
// states
|
||||
const [modalCreateOpen, setModalCreateOpen] = useState<boolean>(false);
|
||||
const [modalProjectCreateOpen, setModalProjectCreateOpen] = useState<boolean>(false);
|
||||
|
||||
|
||||
// derived values
|
||||
const workspaceId = workspace?.id || undefined;
|
||||
const workspaceSlug = workspace?.slug || undefined;
|
||||
const workspaceConnectionId = workspaceConnectionIds[0] || undefined;
|
||||
const entityConnectionMap = entityIds.map((id) => entityById(id));
|
||||
const entityConnection = entityConnectionMap.reduce(
|
||||
(result: { [key: string]: TGitlabEntityConnection[] }, entity) => {
|
||||
if (!entity) return result;
|
||||
const entityConnections = entityConnectionIds.map((id) => {
|
||||
const entityConnection = entityConnectionById(id);
|
||||
if (!entityConnection || (entityConnection.connectionType !== EConnectionType.ENTITY)) {
|
||||
return;
|
||||
}
|
||||
return entityConnection;
|
||||
});
|
||||
|
||||
const projectId = entity?.projectId || "default";
|
||||
|
||||
if (!result[projectId]) result[projectId] = [];
|
||||
result[projectId].push(entity);
|
||||
|
||||
return result;
|
||||
},
|
||||
{}
|
||||
);
|
||||
const projectEntityConnections = entityConnectionIds.map((id) => {
|
||||
const entityConnection = entityConnectionById(id);
|
||||
if (!entityConnection || (entityConnection.connectionType !== EConnectionType.PLANE_PROJECT)) {
|
||||
return;
|
||||
}
|
||||
return entityConnection;
|
||||
});
|
||||
|
||||
// fetching external api token
|
||||
const { isLoading: isGitlabReposLoading } = useSWR(
|
||||
workspaceConnectionId && workspaceId ? `INTEGRATION_GITLAB_REPOS_${workspaceId}_${workspaceConnectionId}` : null,
|
||||
workspaceConnectionId && workspaceId ? async () => fetchGitlabRepositories() : null,
|
||||
const { isLoading: isGitlabEntitiesLoading } = useSWR(
|
||||
workspaceConnectionId && workspaceId ? `INTEGRATION_GITLAB_ENTITIES_${workspaceId}_${workspaceConnectionId}` : null,
|
||||
workspaceConnectionId && workspaceId ? async () => fetchGitlabEntities() : null,
|
||||
{ errorRetryCount: 0 }
|
||||
);
|
||||
|
||||
@@ -82,55 +85,84 @@ export const RepositoryMappingRoot: FC = observer(() => {
|
||||
// fetching entity connections
|
||||
const { isLoading: isEntitiesLoading } = useSWR(
|
||||
workspaceId ? `INTEGRATION_GITLAB_ENTITY_CONNECTIONS_${workspaceId}` : null,
|
||||
workspaceId ? async () => fetchEntities() : null,
|
||||
workspaceId ? async () => fetchEntityConnections() : null,
|
||||
{ errorRetryCount: 0 }
|
||||
);
|
||||
|
||||
|
||||
return (
|
||||
<div className="relative border border-custom-border-200 rounded p-4 space-y-4">
|
||||
{/* heading */}
|
||||
<div className="relative flex justify-between items-center gap-4">
|
||||
<div className="space-y-1">
|
||||
<div className="text-base font-medium">Repository Mapping</div>
|
||||
<div className="text-sm text-custom-text-200">Sync issues from Gitlab repository to Plane projects</div>
|
||||
<div className="space-y-4">
|
||||
<div className="relative border border-custom-border-200 rounded p-4 space-y-4">
|
||||
{/* heading */}
|
||||
<div className="relative flex justify-between items-start gap-4">
|
||||
<div className="space-y-1">
|
||||
<div className="text-base font-medium">Gitlab Project & Group Connections</div>
|
||||
<div className="text-sm text-custom-text-200">Sync issues from Gitlab projects or groups to Plane projects</div>
|
||||
</div>
|
||||
<Button variant="neutral-primary" size="sm" onClick={() => setModalCreateOpen(true)}>
|
||||
Add
|
||||
</Button>
|
||||
</div>
|
||||
<Button variant="neutral-primary" size="sm" onClick={() => setModalCreateOpen(true)}>
|
||||
Add
|
||||
</Button>
|
||||
|
||||
{/* entity connection list */}
|
||||
{
|
||||
isEntitiesLoading && <Loader className="space-y-8">
|
||||
<Loader.Item height="50px" width="40%" />
|
||||
<div className="w-2/3 grid grid-cols-2 gap-x-8 gap-y-4">
|
||||
<Loader.Item height="50px" />
|
||||
<Loader.Item height="50px" />
|
||||
</div>
|
||||
<Loader.Item height="50px" width="20%" />
|
||||
</Loader>
|
||||
}
|
||||
|
||||
{entityConnectionIds && entityConnectionIds.length > 0 && (
|
||||
<div className="relative space-y-2">
|
||||
{entityConnections.map((entityConnection, index) => {
|
||||
if (!entityConnection) return null;
|
||||
return (
|
||||
<div className="space-y-2" key={index}>
|
||||
<EntityConnectionItem key={index} entityConnection={entityConnection} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
<EntityFormCreate modal={modalCreateOpen} handleModal={setModalCreateOpen} />
|
||||
</div>
|
||||
|
||||
{/* mapped blocks */}
|
||||
{entityIds && entityIds.length > 0 && (
|
||||
<div className="relative space-y-2">
|
||||
{Object.keys(entityConnection).map((projectId, index) => {
|
||||
const project = projectId ? getProjectById(projectId) : undefined;
|
||||
if (!project) return null;
|
||||
|
||||
return (
|
||||
<div className="space-y-2" key={index}>
|
||||
<div className="relative flex items-center gap-2 rounded bg-custom-background-90/50 text-base p-2">
|
||||
<div className="flex-shrink-0 relative flex justify-center items-center !w-5 !h-5 rounded-sm bg-custom-background-100">
|
||||
{project && project?.logo_props ? (
|
||||
<Logo logo={project?.logo_props} size={14} />
|
||||
) : (
|
||||
<Briefcase className="w-4 h-4" />
|
||||
)}
|
||||
</div>
|
||||
<div className="text-sm">{project?.name || "Project"}</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
{(entityConnection[projectId] || []).map((connection, index) => (
|
||||
<EntityConnectionItem key={index} project={project} entityConnection={connection} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{/* Add project state mapping blocks */}
|
||||
<div className="relative border border-custom-border-200 rounded p-4 space-y-4">
|
||||
{/* heading */}
|
||||
<div className="relative flex justify-between items-center gap-4">
|
||||
<div className="space-y-1">
|
||||
<div className="text-base font-medium">Plane Project Connections</div>
|
||||
<div className="text-sm text-custom-text-200">Configure pull requests state mapping from Gitlab to Plane projects</div>
|
||||
</div>
|
||||
<Button variant="neutral-primary" size="sm" onClick={() => setModalProjectCreateOpen(true)}>
|
||||
Add
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<FormCreate modal={modalCreateOpen} handleModal={setModalCreateOpen} />
|
||||
{/* Project mapping list */}
|
||||
{entityConnectionIds && entityConnectionIds.length > 0 && (
|
||||
<div className="relative space-y-2">
|
||||
{projectEntityConnections.map((entityConnection, index) => {
|
||||
if (!entityConnection) return null;
|
||||
return (
|
||||
<div className="space-y-2" key={index}>
|
||||
<EntityConnectionItem key={index} entityConnection={entityConnection} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* project entity form */}
|
||||
<ProjectEntityFormCreate modal={modalProjectCreateOpen} handleModal={setModalProjectCreateOpen} />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import axios, { AxiosInstance } from "axios";
|
||||
// plane web types
|
||||
import { TGitlabRepository } from "@/plane-web/types/integrations/gitlab";
|
||||
import { IGitlabEntity } from "@plane/etl/gitlab";
|
||||
|
||||
export class GitlabDataService {
|
||||
protected baseURL: string;
|
||||
@@ -23,4 +24,17 @@ export class GitlabDataService {
|
||||
.catch((error) => {
|
||||
throw error?.response?.data;
|
||||
});
|
||||
|
||||
/**
|
||||
* @description fetch gitlab entities
|
||||
* @param { string } workspaceId
|
||||
* @returns { Promise<IGitlabEntity[]> }
|
||||
*/
|
||||
fetchGitlabEntities = async (workspaceId: string): Promise<IGitlabEntity[]> =>
|
||||
await this.axiosInstance
|
||||
.get(`/api/gitlab/entities/${workspaceId}`)
|
||||
.then((res) => res.data)
|
||||
.catch((error) => {
|
||||
throw error?.response?.data;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -14,15 +14,14 @@ export class GitlabEntityService {
|
||||
/**
|
||||
* @description fetch entity connections
|
||||
* @param { string } workspaceId
|
||||
* @param { string } workspaceConnectionId
|
||||
* @param { string } connectionType
|
||||
* @returns { Promise<TGitlabEntityConnection[] | undefined> }
|
||||
*/
|
||||
fetchEntityConnections = async (
|
||||
workspaceId: string,
|
||||
workspaceConnectionId: string
|
||||
): Promise<TGitlabEntityConnection[] | undefined> =>
|
||||
await this.axiosInstance
|
||||
.get(`/api/entity-connections/${workspaceId}/${workspaceConnectionId}`)
|
||||
.get(`/api/gitlab/entity-connections/${workspaceId}`)
|
||||
.then((res) => res.data)
|
||||
.catch((error) => {
|
||||
throw error?.response?.data;
|
||||
@@ -30,18 +29,14 @@ export class GitlabEntityService {
|
||||
|
||||
/**
|
||||
* @description fetch entity connection
|
||||
* @param { string } workspaceId
|
||||
* @param { string } workspaceConnectionId
|
||||
* @param { string } entityId
|
||||
* @param { string } connectionId
|
||||
* @returns { Promise<TGitlabEntityConnection | undefined> }
|
||||
*/
|
||||
fetchEntityConnection = async (
|
||||
workspaceId: string,
|
||||
workspaceConnectionId: string,
|
||||
entityId: string
|
||||
connectionId: string,
|
||||
): Promise<TGitlabEntityConnection | undefined> =>
|
||||
await this.axiosInstance
|
||||
.get(`/api/entity-connections/${workspaceId}/${workspaceConnectionId}/${entityId}`)
|
||||
.get(`/api/entity-connections/${connectionId}`)
|
||||
.then((res) => res.data)
|
||||
.catch((error) => {
|
||||
throw error?.response?.data;
|
||||
@@ -60,7 +55,7 @@ export class GitlabEntityService {
|
||||
entityConnection: Partial<TGitlabEntityConnection>
|
||||
): Promise<TGitlabEntityConnection | undefined> =>
|
||||
await this.axiosInstance
|
||||
.post(`/api/entity-connections/${workspaceId}/${workspaceConnectionId}`, entityConnection)
|
||||
.post(`/api/gitlab/entity-connections/${workspaceId}/${workspaceConnectionId}`, entityConnection)
|
||||
.then((res) => res.data)
|
||||
.catch((error) => {
|
||||
throw error?.response?.data;
|
||||
@@ -68,20 +63,16 @@ export class GitlabEntityService {
|
||||
|
||||
/**
|
||||
* @description update entity connection
|
||||
* @param { string } workspaceId
|
||||
* @param { string } workspaceConnectionId
|
||||
* @param { string } entityId
|
||||
* @param { string } connectionId
|
||||
* @param { Partial<TGitlabEntityConnection> } entityConnection
|
||||
* @returns { Promise<TGitlabEntityConnection | undefined> }
|
||||
*/
|
||||
updateEntityConnection = async (
|
||||
workspaceId: string,
|
||||
workspaceConnectionId: string,
|
||||
entityId: string,
|
||||
connectionId: string,
|
||||
entityConnection: Partial<TGitlabEntityConnection>
|
||||
): Promise<TGitlabEntityConnection | undefined> =>
|
||||
await this.axiosInstance
|
||||
.put(`/api/entity-connections/${workspaceId}/${workspaceConnectionId}/${entityId}`, entityConnection)
|
||||
.put(`/api/entity-connections/${connectionId}`, entityConnection)
|
||||
.then((res) => res.data)
|
||||
.catch((error) => {
|
||||
throw error?.response?.data;
|
||||
@@ -89,20 +80,35 @@ export class GitlabEntityService {
|
||||
|
||||
/**
|
||||
* @description delete entity connection
|
||||
* @param { string } workspaceId
|
||||
* @param { string } workspaceConnectionId
|
||||
* @param { string } entityId
|
||||
* @param { string } connectionId
|
||||
* @returns { Promise<void> }
|
||||
*/
|
||||
deleteEntityConnection = async (
|
||||
workspaceId: string,
|
||||
workspaceConnectionId: string,
|
||||
entityId: string
|
||||
connectionId: string,
|
||||
): Promise<void> =>
|
||||
await this.axiosInstance
|
||||
.delete(`/api/entity-connections/${workspaceId}/${workspaceConnectionId}/${entityId}`)
|
||||
.delete(`/api/entity-connections/${connectionId}`)
|
||||
.then(() => undefined)
|
||||
.catch((error) => {
|
||||
throw error?.response?.data;
|
||||
});
|
||||
|
||||
/**
|
||||
* @description create project entity connection
|
||||
* @param { string } workspaceId
|
||||
* @param { string } workspaceConnectionId
|
||||
* @param { Partial<TGitlabEntityConnection> } entityConnection
|
||||
* @returns { Promise<TGitlabEntityConnection | undefined> }
|
||||
*/
|
||||
createProjectEntityConnection = async (
|
||||
workspaceId: string,
|
||||
workspaceConnectionId: string,
|
||||
entityConnection: Partial<TGitlabEntityConnection>
|
||||
): Promise<TGitlabEntityConnection | undefined> =>
|
||||
await this.axiosInstance
|
||||
.post(`/api/gitlab/entity-project-connections/${workspaceId}/${workspaceConnectionId}`, entityConnection)
|
||||
.then((res) => res.data)
|
||||
.catch((error) => {
|
||||
throw error?.response?.data;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,26 +9,33 @@ import { GitlabDataService } from "@/plane-web/services/integrations/gitlab";
|
||||
import { IGitlabStore } from "@/plane-web/store/integrations";
|
||||
// plane web types
|
||||
import { TGitlabRepository } from "@/plane-web/types/integrations/gitlab";
|
||||
import { IGitlabEntity } from "@plane/etl/gitlab";
|
||||
|
||||
export interface IGitlabDataStore {
|
||||
// store instances
|
||||
gitlabRepositories: Record<string, Record<string, TGitlabRepository>>; // organizationId -> gitlabRepositoryId -> TGitlabRepository
|
||||
gitlabUsers: Record<string, Record<string, object>>; // organizationId -> gitlabUserId -> gitlabUser
|
||||
gitlabEntities: Record<string, Record<string, IGitlabEntity>>; // organizationId -> gitlabRepositoryId -> IGitlabEntity
|
||||
// computed
|
||||
gitlabRepositoryIds: string[];
|
||||
gitlabUserIds: string[] | undefined;
|
||||
gitlabEntityIds: string[] | undefined;
|
||||
// computed functions
|
||||
gitlabRepositoryById: (gitlabRepositoryId: string) => TGitlabRepository | undefined;
|
||||
gitlabUserById: (gitlabUserId: string) => object | undefined;
|
||||
gitlabEntityById: (gitlabEntityId: string) => IGitlabEntity | undefined;
|
||||
// actions
|
||||
fetchGitlabRepositories: () => Promise<object | undefined>;
|
||||
fetchGitlabUsers: () => Promise<object | undefined>;
|
||||
fetchGitlabEntities: () => Promise<IGitlabEntity[] | undefined>;
|
||||
}
|
||||
|
||||
export class GitlabDataStore implements IGitlabDataStore {
|
||||
// observables
|
||||
gitlabRepositories: Record<string, Record<string, TGitlabRepository>> = {}; // organizationId -> gitlabRepositoryId -> TGitlabRepository
|
||||
gitlabUsers: Record<string, Record<string, object>> = {}; // organizationId -> gitlabUserId -> gitlabUser
|
||||
gitlabEntities: Record<string, Record<string, IGitlabEntity>> = {}; // organizationId -> gitlabRepositoryId -> IGitlabEntity
|
||||
|
||||
// service
|
||||
private service: GitlabDataService;
|
||||
|
||||
@@ -37,12 +44,15 @@ export class GitlabDataStore implements IGitlabDataStore {
|
||||
// observables
|
||||
gitlabRepositories: observable,
|
||||
gitlabUsers: observable,
|
||||
gitlabEntities: observable,
|
||||
// computed
|
||||
gitlabRepositoryIds: computed,
|
||||
gitlabUserIds: computed,
|
||||
gitlabEntityIds: computed,
|
||||
// computed functions
|
||||
fetchGitlabRepositories: action,
|
||||
fetchGitlabUsers: action,
|
||||
fetchGitlabEntities: action,
|
||||
});
|
||||
|
||||
this.service = new GitlabDataService(encodeURI(SILO_BASE_URL + SILO_BASE_PATH));
|
||||
@@ -77,6 +87,20 @@ export class GitlabDataStore implements IGitlabDataStore {
|
||||
return Object.keys(gitlabUsers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description get gitlab entity ids
|
||||
* @returns { string[] | undefined }
|
||||
*/
|
||||
get gitlabEntityIds(): string[] | undefined {
|
||||
const organizationId = this.store.auth.workspaceConnectionIds[0];
|
||||
if (!organizationId) return;
|
||||
|
||||
const gitlabEntities = this.gitlabEntities[organizationId];
|
||||
if (!gitlabEntities) return;
|
||||
|
||||
return Object.keys(gitlabEntities);
|
||||
}
|
||||
|
||||
// computed functions
|
||||
/**
|
||||
* @description get gitlab repository by id
|
||||
@@ -108,6 +132,22 @@ export class GitlabDataStore implements IGitlabDataStore {
|
||||
return gitlabUsers[gitlabUserId] || undefined;
|
||||
});
|
||||
|
||||
/**
|
||||
* @description get gitlab entity by id
|
||||
* @param { string } gitlabEntityId
|
||||
* @returns { IGitlabEntity | undefined }
|
||||
*/
|
||||
gitlabEntityById = computedFn((gitlabEntityId: string): IGitlabEntity | undefined => {
|
||||
const organizationId = this.store.auth.workspaceConnectionIds[0];
|
||||
if (!organizationId) return;
|
||||
|
||||
const gitlabEntities = this.gitlabEntities[organizationId];
|
||||
if (!gitlabEntities) return;
|
||||
|
||||
return gitlabEntities[gitlabEntityId] || undefined;
|
||||
});
|
||||
|
||||
|
||||
// actions
|
||||
/**
|
||||
* @description fetch gitlab repositories
|
||||
@@ -151,4 +191,32 @@ export class GitlabDataStore implements IGitlabDataStore {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @description fetch gitlab entities
|
||||
* @returns { Promise<IGitlabEntity[]> }
|
||||
*/
|
||||
fetchGitlabEntities = async (): Promise<IGitlabEntity[]> => {
|
||||
try {
|
||||
const workspaceId = this.store.workspace?.id;
|
||||
const organizationId = this.store.auth.workspaceConnectionIds[0];
|
||||
|
||||
if (!workspaceId || !organizationId) return [];
|
||||
|
||||
const response = await this.service.fetchGitlabEntities(workspaceId);
|
||||
|
||||
if (response) {
|
||||
runInAction(() => {
|
||||
response.forEach((data) => {
|
||||
this.gitlabEntities[organizationId] = this.gitlabEntities[organizationId] || {};
|
||||
this.gitlabEntities[organizationId][data.id] = data;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,43 +11,46 @@ import { GitlabEntityService } from "@/plane-web/services/integrations/gitlab";
|
||||
import { IGitlabStore } from "@/plane-web/store/integrations";
|
||||
// plane web types
|
||||
import { TGitlabEntityConnection } from "@/plane-web/types/integrations/gitlab";
|
||||
import { EConnectionType, GitlabEntityType } from "@plane/etl/gitlab";
|
||||
|
||||
export interface IGitlabEntityStore {
|
||||
export interface IGitlabEntityConnectionStore {
|
||||
// store instances
|
||||
entityMap: Record<string, Record<string, Record<string, TGitlabEntityConnection>>>; // workspaceId -> workspaceConnectionId -> entityId -> entity
|
||||
// computed
|
||||
entityIds: string[];
|
||||
entityConnectionMap: Record<string, Record<string, Record<string, TGitlabEntityConnection>>>; // workspaceId -> workspaceConnectionId -> connectionId -> entity
|
||||
// computed
|
||||
entityConnectionIds: string[];
|
||||
// computed functions
|
||||
entityById: (entityId: string) => TGitlabEntityConnection | undefined;
|
||||
entityConnectionById: (entityId: string) => TGitlabEntityConnection | undefined;
|
||||
// actions
|
||||
fetchEntities: () => Promise<TGitlabEntityConnection[] | undefined>;
|
||||
fetchEntity: (entityId: string) => Promise<TGitlabEntityConnection | undefined>;
|
||||
createEntity: (entity: Partial<TGitlabEntityConnection>) => Promise<TGitlabEntityConnection | undefined>;
|
||||
updateEntity: (
|
||||
entityId: string,
|
||||
fetchEntityConnections: () => Promise<TGitlabEntityConnection[] | undefined>;
|
||||
fetchEntityConnection: (entityId: string) => Promise<TGitlabEntityConnection | undefined>;
|
||||
createEntityConnection: (entity: Partial<TGitlabEntityConnection>) => Promise<TGitlabEntityConnection | undefined>;
|
||||
createProjectConnection: (entity: Partial<TGitlabEntityConnection>) => Promise<TGitlabEntityConnection | undefined>;
|
||||
updateEntityConnection: (
|
||||
connectionId: string,
|
||||
entity: Partial<TGitlabEntityConnection>
|
||||
) => Promise<TGitlabEntityConnection | undefined>;
|
||||
deleteEntity: (entityId: string) => Promise<void | undefined>;
|
||||
deleteEntityConnection: (connectionId: string) => Promise<void | undefined>;
|
||||
}
|
||||
|
||||
export class GitlabEntityStore implements IGitlabEntityStore {
|
||||
export class GitlabEntityStore implements IGitlabEntityConnectionStore {
|
||||
// observables
|
||||
entityMap: Record<string, Record<string, Record<string, TGitlabEntityConnection>>> = {}; // workspaceId -> workspaceConnectionId -> entityId -> entity
|
||||
entityConnectionMap: Record<string, Record<string, Record<string, TGitlabEntityConnection>>> = {}; // workspaceId -> workspaceConnectionId -> connectionId -> entity
|
||||
// service
|
||||
private service: GitlabEntityService;
|
||||
|
||||
constructor(protected store: IGitlabStore) {
|
||||
makeObservable(this, {
|
||||
// observables
|
||||
entityMap: observable,
|
||||
entityConnectionMap: observable,
|
||||
// computed
|
||||
entityIds: computed,
|
||||
entityConnectionIds: computed,
|
||||
// actions
|
||||
fetchEntities: action,
|
||||
fetchEntity: action,
|
||||
createEntity: action,
|
||||
updateEntity: action,
|
||||
deleteEntity: action,
|
||||
fetchEntityConnections: action,
|
||||
fetchEntityConnection: action,
|
||||
createEntityConnection: action,
|
||||
createProjectConnection: action,
|
||||
updateEntityConnection: action,
|
||||
deleteEntityConnection: action,
|
||||
});
|
||||
|
||||
this.service = new GitlabEntityService(encodeURI(SILO_BASE_URL + SILO_BASE_PATH));
|
||||
@@ -58,27 +61,27 @@ export class GitlabEntityStore implements IGitlabEntityStore {
|
||||
* @description get entity ids
|
||||
* @returns { string[] }
|
||||
*/
|
||||
get entityIds(): string[] {
|
||||
get entityConnectionIds(): string[] {
|
||||
const workspaceId = this.store.workspace?.id || undefined;
|
||||
const workspaceConnectionId = this.store.auth.workspaceConnectionIds[0] || undefined;
|
||||
if (!workspaceId || !workspaceConnectionId || !this.entityMap?.[workspaceId]?.[workspaceConnectionId]) return [];
|
||||
if (!workspaceId || !workspaceConnectionId || !this.entityConnectionMap?.[workspaceId]?.[workspaceConnectionId]) return [];
|
||||
|
||||
return Object.keys(this.entityMap[workspaceId][workspaceConnectionId]);
|
||||
return Object.keys(this.entityConnectionMap[workspaceId][workspaceConnectionId]);
|
||||
}
|
||||
|
||||
// computed functions
|
||||
/**
|
||||
* @description get entity by id
|
||||
* @param { string } entityId
|
||||
* @param { string } connectionId
|
||||
* @returns { TGitlabEntityConnection | undefined }
|
||||
*/
|
||||
entityById = computedFn((entityId: string): TGitlabEntityConnection | undefined => {
|
||||
entityConnectionById = computedFn((connectionId: string): TGitlabEntityConnection | undefined => {
|
||||
const workspaceId = this.store.workspace?.id || undefined;
|
||||
const workspaceConnectionId = this.store.auth.workspaceConnectionIds[0] || undefined;
|
||||
if (!workspaceId || !workspaceConnectionId || !entityId || !this.entityMap?.[workspaceId]?.[workspaceConnectionId])
|
||||
if (!workspaceId || !workspaceConnectionId || !connectionId || !this.entityConnectionMap?.[workspaceId]?.[workspaceConnectionId])
|
||||
return undefined;
|
||||
|
||||
return this.entityMap[workspaceId][workspaceConnectionId][entityId];
|
||||
return this.entityConnectionMap[workspaceId][workspaceConnectionId][connectionId];
|
||||
});
|
||||
|
||||
// actions
|
||||
@@ -86,18 +89,18 @@ export class GitlabEntityStore implements IGitlabEntityStore {
|
||||
* @description fetch entities
|
||||
* @returns { Promise<TGitlabEntityConnection[] | undefined> }
|
||||
*/
|
||||
fetchEntities = async (): Promise<TGitlabEntityConnection[] | undefined> => {
|
||||
fetchEntityConnections = async (): Promise<TGitlabEntityConnection[] | undefined> => {
|
||||
try {
|
||||
const workspaceId = this.store.workspace?.id || undefined;
|
||||
const workspaceConnectionId = this.store.auth.workspaceConnectionIds[0] || undefined;
|
||||
if (!workspaceId || !workspaceConnectionId) return;
|
||||
|
||||
const response = await this.service.fetchEntityConnections(workspaceId, workspaceConnectionId);
|
||||
const response = await this.service.fetchEntityConnections(workspaceId);
|
||||
|
||||
if (response) {
|
||||
runInAction(() => {
|
||||
response.forEach((data) => {
|
||||
set(this.entityMap, [workspaceId, workspaceConnectionId, data.id], data);
|
||||
set(this.entityConnectionMap, [workspaceId, workspaceConnectionId, data.id], data);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -110,20 +113,20 @@ export class GitlabEntityStore implements IGitlabEntityStore {
|
||||
|
||||
/**
|
||||
* @description fetch entity
|
||||
* @param { string } entityId
|
||||
* @param { string } connectionId
|
||||
* @returns { Promise<TGitlabEntityConnection | undefined> }
|
||||
*/
|
||||
fetchEntity = async (entityId: string): Promise<TGitlabEntityConnection | undefined> => {
|
||||
fetchEntityConnection = async (connectionId: string): Promise<TGitlabEntityConnection | undefined> => {
|
||||
try {
|
||||
const workspaceId = this.store.workspace?.id || undefined;
|
||||
const workspaceConnectionId = this.store.auth.workspaceConnectionIds[0] || undefined;
|
||||
if (!workspaceId || !workspaceConnectionId || !entityId) return;
|
||||
if (!workspaceId || !workspaceConnectionId || !connectionId) return;
|
||||
|
||||
const response = await this.service.fetchEntityConnection(workspaceId, workspaceConnectionId, entityId);
|
||||
const response = await this.service.fetchEntityConnection(connectionId);
|
||||
|
||||
if (response) {
|
||||
runInAction(() => {
|
||||
set(this.entityMap, [workspaceId, workspaceConnectionId, response.id], response);
|
||||
set(this.entityConnectionMap, [workspaceId, workspaceConnectionId, response.id], response);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -138,18 +141,18 @@ export class GitlabEntityStore implements IGitlabEntityStore {
|
||||
* @param { Partial<TGitlabEntityConnection> } entity
|
||||
* @returns { Promise<TGitlabEntityConnection | undefined> }
|
||||
*/
|
||||
createEntity = async (entity: Partial<TGitlabEntityConnection>): Promise<TGitlabEntityConnection | undefined> => {
|
||||
createEntityConnection = async (entity: Partial<TGitlabEntityConnection>): Promise<TGitlabEntityConnection | undefined> => {
|
||||
try {
|
||||
const workspaceId = this.store.workspace?.id || undefined;
|
||||
const workspaceSlug = this.store.workspace?.slug || undefined;
|
||||
const workspaceConnectionId = this.store.auth.workspaceConnectionIds[0] || undefined;
|
||||
if (!workspaceId || !workspaceSlug || !workspaceConnectionId) return;
|
||||
|
||||
const gitlabRepoId = entity?.entityId || undefined;
|
||||
if (!gitlabRepoId) return;
|
||||
const gitlabEntityId = entity?.entityId || undefined;
|
||||
if (!gitlabEntityId) return;
|
||||
|
||||
const gitlabRepo = this.store.data.gitlabRepositoryById(gitlabRepoId) || undefined;
|
||||
if (!gitlabRepo) return;
|
||||
const gitlabEntity = this.store.data.gitlabEntityById(gitlabEntityId) || undefined;
|
||||
if (!gitlabEntity) return;
|
||||
|
||||
const payload: Partial<TGitlabEntityConnection> = {
|
||||
workspaceId: workspaceId,
|
||||
@@ -157,8 +160,9 @@ export class GitlabEntityStore implements IGitlabEntityStore {
|
||||
projectId: entity.projectId,
|
||||
workspaceConnectionId: workspaceConnectionId,
|
||||
entityId: entity.entityId,
|
||||
entitySlug: gitlabRepo.full_name,
|
||||
entityData: gitlabRepo,
|
||||
entityType: gitlabEntity.type,
|
||||
entitySlug: gitlabEntity.name,
|
||||
entityData: gitlabEntity,
|
||||
config: entity.config,
|
||||
};
|
||||
|
||||
@@ -166,11 +170,42 @@ export class GitlabEntityStore implements IGitlabEntityStore {
|
||||
|
||||
if (response) {
|
||||
runInAction(() => {
|
||||
set(this.entityMap, [workspaceId, workspaceConnectionId, response.id], response);
|
||||
set(this.entityConnectionMap, [workspaceId, workspaceConnectionId, response.id], response);
|
||||
});
|
||||
}
|
||||
|
||||
await this.fetchEntities();
|
||||
await this.fetchEntityConnections();
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
createProjectConnection = async (entity: Partial<TGitlabEntityConnection>): Promise<TGitlabEntityConnection | undefined> => {
|
||||
try {
|
||||
const workspaceId = this.store.workspace?.id || undefined;
|
||||
const workspaceSlug = this.store.workspace?.slug || undefined;
|
||||
const workspaceConnectionId = this.store.auth.workspaceConnectionIds[0] || undefined;
|
||||
if (!workspaceId || !workspaceSlug || !workspaceConnectionId) return;
|
||||
|
||||
const payload: Partial<TGitlabEntityConnection> = {
|
||||
workspaceId: workspaceId,
|
||||
workspaceSlug: workspaceSlug,
|
||||
projectId: entity.projectId,
|
||||
workspaceConnectionId: workspaceConnectionId,
|
||||
config: entity.config,
|
||||
};
|
||||
|
||||
const response = await this.service.createProjectEntityConnection(workspaceId, workspaceConnectionId, payload);
|
||||
|
||||
if (response) {
|
||||
runInAction(() => {
|
||||
set(this.entityConnectionMap, [workspaceId, workspaceConnectionId, response.id], response);
|
||||
});
|
||||
}
|
||||
|
||||
await this.fetchEntityConnections();
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
@@ -180,42 +215,33 @@ export class GitlabEntityStore implements IGitlabEntityStore {
|
||||
|
||||
/**
|
||||
* @description update entity
|
||||
* @param { string } entityId
|
||||
* @param { string } connectionId
|
||||
* @param { Partial<TGitlabEntityConnection> } entity
|
||||
* @returns { Promise<TGitlabEntityConnection | undefined> }
|
||||
*/
|
||||
updateEntity = async (
|
||||
entityId: string,
|
||||
updateEntityConnection = async (
|
||||
connectionId: string,
|
||||
entity: Partial<TGitlabEntityConnection>
|
||||
): Promise<TGitlabEntityConnection | undefined> => {
|
||||
try {
|
||||
const workspaceId = this.store.workspace?.id || undefined;
|
||||
const workspaceSlug = this.store.workspace?.slug || undefined;
|
||||
const workspaceConnectionId = this.store.auth.workspaceConnectionIds[0] || undefined;
|
||||
if (!workspaceId || !workspaceSlug || !workspaceConnectionId || !entityId) return;
|
||||
|
||||
const gitlabRepoId = entity?.entityId || undefined;
|
||||
if (!gitlabRepoId) return;
|
||||
|
||||
const gitlabRepo = this.store.data.gitlabRepositoryById(gitlabRepoId) || undefined;
|
||||
if (!gitlabRepo) return;
|
||||
if (!workspaceId || !workspaceSlug || !workspaceConnectionId || !connectionId) return;
|
||||
|
||||
const payload: Partial<TGitlabEntityConnection> = {
|
||||
workspaceId: workspaceId,
|
||||
workspaceSlug: workspaceSlug,
|
||||
projectId: entity.projectId,
|
||||
workspaceConnectionId: workspaceConnectionId,
|
||||
entityId: entity.entityId,
|
||||
entitySlug: gitlabRepo.full_name,
|
||||
entityData: gitlabRepo,
|
||||
config: entity.config,
|
||||
};
|
||||
|
||||
const response = await this.service.updateEntityConnection(workspaceId, workspaceConnectionId, entityId, payload);
|
||||
const response = await this.service.updateEntityConnection(connectionId, payload);
|
||||
|
||||
if (response) {
|
||||
runInAction(() => {
|
||||
set(this.entityMap, [workspaceId, workspaceConnectionId, response.id], response);
|
||||
set(this.entityConnectionMap, [workspaceId, workspaceConnectionId, response.id], response);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -227,17 +253,17 @@ export class GitlabEntityStore implements IGitlabEntityStore {
|
||||
|
||||
/**
|
||||
* @description delete entity
|
||||
* @param { string } entityId
|
||||
* @param { string } connectionId
|
||||
* @returns { Promise<void | undefined> }
|
||||
*/
|
||||
deleteEntity = async (entityId: string): Promise<void | undefined> => {
|
||||
deleteEntityConnection = async (connectionId: string): Promise<void | undefined> => {
|
||||
try {
|
||||
const workspaceId = this.store.workspace?.id || undefined;
|
||||
const workspaceConnectionId = this.store.auth.workspaceConnectionIds[0] || undefined;
|
||||
if (!workspaceId || !workspaceConnectionId || !entityId) return;
|
||||
if (!workspaceId || !workspaceConnectionId || !connectionId) return;
|
||||
|
||||
await this.service.deleteEntityConnection(workspaceId, workspaceConnectionId, entityId);
|
||||
unset(this.entityMap, [workspaceId, workspaceConnectionId, entityId]);
|
||||
await this.service.deleteEntityConnection(connectionId);
|
||||
unset(this.entityConnectionMap, [workspaceId, workspaceConnectionId, connectionId]);
|
||||
|
||||
return;
|
||||
} catch (error) {
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
GitlabAuthStore,
|
||||
IGitlabDataStore,
|
||||
GitlabDataStore,
|
||||
IGitlabEntityStore,
|
||||
IGitlabEntityConnectionStore,
|
||||
GitlabEntityStore,
|
||||
} from "@/plane-web/store/integrations";
|
||||
import { RootStore } from "@/plane-web/store/root.store";
|
||||
@@ -17,14 +17,14 @@ export interface IGitlabStore extends IIntegrationBaseStore {
|
||||
// store instances
|
||||
auth: IGitlabAuthStore;
|
||||
data: IGitlabDataStore;
|
||||
entity: IGitlabEntityStore;
|
||||
entityConnection: IGitlabEntityConnectionStore;
|
||||
}
|
||||
|
||||
export class GitlabStore extends IntegrationBaseStore implements IGitlabStore {
|
||||
// store instances
|
||||
auth: IGitlabAuthStore;
|
||||
data: IGitlabDataStore;
|
||||
entity: IGitlabEntityStore;
|
||||
entityConnection: IGitlabEntityConnectionStore;
|
||||
|
||||
constructor(protected store: RootStore) {
|
||||
super(store);
|
||||
@@ -33,6 +33,6 @@ export class GitlabStore extends IntegrationBaseStore implements IGitlabStore {
|
||||
// store instances
|
||||
this.auth = new GitlabAuthStore(this);
|
||||
this.data = new GitlabDataStore(this);
|
||||
this.entity = new GitlabEntityStore(this);
|
||||
this.entityConnection = new GitlabEntityStore(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { TGitlabWorkspaceConnectionData, TWorkspaceConnection } from "@plane/etl/core";
|
||||
import { EConnectionType, GitlabEntityType, IGitlabEntity } from "@plane/etl/gitlab";
|
||||
import { IState } from "@plane/sdk";
|
||||
|
||||
// auth types
|
||||
@@ -48,14 +49,13 @@ export type TGitlabEntityConnection = {
|
||||
|
||||
entityId: string;
|
||||
entitySlug: string;
|
||||
entityData: object & {
|
||||
id: number;
|
||||
name: string;
|
||||
full_name: string;
|
||||
};
|
||||
entityData: IGitlabEntity;
|
||||
entityType: GitlabEntityType;
|
||||
|
||||
config: TGitlabEntityConnectionConfig;
|
||||
|
||||
connectionType: keyof typeof EConnectionType;
|
||||
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
597
yarn.lock
597
yarn.lock
@@ -1815,62 +1815,62 @@
|
||||
prop-types "^15.8.1"
|
||||
react-is "^19.0.0"
|
||||
|
||||
"@next/env@14.2.22":
|
||||
version "14.2.22"
|
||||
resolved "https://registry.yarnpkg.com/@next/env/-/env-14.2.22.tgz#8898ae47595badbfacebfc1585f42a4e06a97301"
|
||||
integrity sha512-EQ6y1QeNQglNmNIXvwP/Bb+lf7n9WtgcWvtoFsHquVLCJUuxRs+6SfZ5EK0/EqkkLex4RrDySvKgKNN7PXip7Q==
|
||||
"@next/env@14.2.21":
|
||||
version "14.2.21"
|
||||
resolved "https://registry.yarnpkg.com/@next/env/-/env-14.2.21.tgz#09ff0813d29c596397e141205d4f5fd5c236bdd0"
|
||||
integrity sha512-lXcwcJd5oR01tggjWJ6SrNNYFGuOOMB9c251wUNkjCpkoXOPkDeF/15c3mnVlBqrW4JJXb2kVxDFhC4GduJt2A==
|
||||
|
||||
"@next/eslint-plugin-next@14.2.22":
|
||||
version "14.2.22"
|
||||
resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-14.2.22.tgz#4de757f8e430c18b1d1e1b92ff2fe45754d8c641"
|
||||
integrity sha512-8xCmBMd+hUapMpviPp5g3oDhoWRtbE/QeN/Nvth+SZrdt7xt9TBsH8cePkRwRjXFpwHndpRDNVQROxR/1HiVbg==
|
||||
"@next/eslint-plugin-next@14.2.21":
|
||||
version "14.2.21"
|
||||
resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-14.2.21.tgz#3e5b96cec21ba76c1e316938f74e32ce1d09f554"
|
||||
integrity sha512-bxfiExnMkpwo4bBhCqnDhdgFyxSp6Xt6xu4Ne7En6MpgqwiER95Or+q1WDUDX4e888taeIAdPIAVaY+Wv0kiwQ==
|
||||
dependencies:
|
||||
glob "10.3.10"
|
||||
|
||||
"@next/swc-darwin-arm64@14.2.22":
|
||||
version "14.2.22"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.22.tgz#2b3fcb42247ba951b19a48fc03f1d6fe65629baa"
|
||||
integrity sha512-HUaLiehovgnqY4TMBZJ3pDaOsTE1spIXeR10pWgdQVPYqDGQmHJBj3h3V6yC0uuo/RoY2GC0YBFRkOX3dI9WVQ==
|
||||
"@next/swc-darwin-arm64@14.2.21":
|
||||
version "14.2.21"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.21.tgz#32a31992aace1440981df9cf7cb3af7845d94fec"
|
||||
integrity sha512-HwEjcKsXtvszXz5q5Z7wCtrHeTTDSTgAbocz45PHMUjU3fBYInfvhR+ZhavDRUYLonm53aHZbB09QtJVJj8T7g==
|
||||
|
||||
"@next/swc-darwin-x64@14.2.22":
|
||||
version "14.2.22"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.22.tgz#11ecc609e9530b3edf8ddfd1fd3bd6aca4e1bfda"
|
||||
integrity sha512-ApVDANousaAGrosWvxoGdLT0uvLBUC+srqOcpXuyfglA40cP2LBFaGmBjhgpxYk5z4xmunzqQvcIgXawTzo2uQ==
|
||||
"@next/swc-darwin-x64@14.2.21":
|
||||
version "14.2.21"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.21.tgz#5ab4b3f6685b6b52f810d0f5cf6e471480ddffdb"
|
||||
integrity sha512-TSAA2ROgNzm4FhKbTbyJOBrsREOMVdDIltZ6aZiKvCi/v0UwFmwigBGeqXDA97TFMpR3LNNpw52CbVelkoQBxA==
|
||||
|
||||
"@next/swc-linux-arm64-gnu@14.2.22":
|
||||
version "14.2.22"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.22.tgz#4c08dd223e50c348f561af2285e27fb326ffabbf"
|
||||
integrity sha512-3O2J99Bk9aM+d4CGn9eEayJXHuH9QLx0BctvWyuUGtJ3/mH6lkfAPRI4FidmHMBQBB4UcvLMfNf8vF0NZT7iKw==
|
||||
"@next/swc-linux-arm64-gnu@14.2.21":
|
||||
version "14.2.21"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.21.tgz#8a0e1fa887aef19ca218af2af515d0a5ee67ba3f"
|
||||
integrity sha512-0Dqjn0pEUz3JG+AImpnMMW/m8hRtl1GQCNbO66V1yp6RswSTiKmnHf3pTX6xMdJYSemf3O4Q9ykiL0jymu0TuA==
|
||||
|
||||
"@next/swc-linux-arm64-musl@14.2.22":
|
||||
version "14.2.22"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.22.tgz#0b285336f145887d421b3762f3d7c75f847ec1b3"
|
||||
integrity sha512-H/hqfRz75yy60y5Eg7DxYfbmHMjv60Dsa6IWHzpJSz4MRkZNy5eDnEW9wyts9bkxwbOVZNPHeb3NkqanP+nGPg==
|
||||
"@next/swc-linux-arm64-musl@14.2.21":
|
||||
version "14.2.21"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.21.tgz#ddad844406b42fa8965fe11250abc85c1fe0fd05"
|
||||
integrity sha512-Ggfw5qnMXldscVntwnjfaQs5GbBbjioV4B4loP+bjqNEb42fzZlAaK+ldL0jm2CTJga9LynBMhekNfV8W4+HBw==
|
||||
|
||||
"@next/swc-linux-x64-gnu@14.2.22":
|
||||
version "14.2.22"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.22.tgz#a936b6cfea0364571102f0389c6368d6acf3e294"
|
||||
integrity sha512-LckLwlCLcGR1hlI5eiJymR8zSHPsuruuwaZ3H2uudr25+Dpzo6cRFjp/3OR5UYJt8LSwlXv9mmY4oI2QynwpqQ==
|
||||
"@next/swc-linux-x64-gnu@14.2.21":
|
||||
version "14.2.21"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.21.tgz#db55fd666f9ba27718f65caa54b622a912cdd16b"
|
||||
integrity sha512-uokj0lubN1WoSa5KKdThVPRffGyiWlm/vCc/cMkWOQHw69Qt0X1o3b2PyLLx8ANqlefILZh1EdfLRz9gVpG6tg==
|
||||
|
||||
"@next/swc-linux-x64-musl@14.2.22":
|
||||
version "14.2.22"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.22.tgz#0359497840d0b7d8c095d0d9735bc6aec68cef5d"
|
||||
integrity sha512-qGUutzmh0PoFU0fCSu0XYpOfT7ydBZgDfcETIeft46abPqP+dmePhwRGLhFKwZWxNWQCPprH26TjaTxM0Nv8mw==
|
||||
"@next/swc-linux-x64-musl@14.2.21":
|
||||
version "14.2.21"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.21.tgz#dddb850353624efcd58c4c4e30ad8a1aab379642"
|
||||
integrity sha512-iAEBPzWNbciah4+0yI4s7Pce6BIoxTQ0AGCkxn/UBuzJFkYyJt71MadYQkjPqCQCJAFQ26sYh7MOKdU+VQFgPg==
|
||||
|
||||
"@next/swc-win32-arm64-msvc@14.2.22":
|
||||
version "14.2.22"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.22.tgz#9fd249d49ffccf3388400ab24472c432cdd04c24"
|
||||
integrity sha512-K6MwucMWmIvMb9GlvT0haYsfIPxfQD8yXqxwFy4uLFMeXIb2TcVYQimxkaFZv86I7sn1NOZnpOaVk5eaxThGIw==
|
||||
"@next/swc-win32-arm64-msvc@14.2.21":
|
||||
version "14.2.21"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.21.tgz#290012ee57b196d3d2d04853e6bf0179cae9fbaf"
|
||||
integrity sha512-plykgB3vL2hB4Z32W3ktsfqyuyGAPxqwiyrAi2Mr8LlEUhNn9VgkiAl5hODSBpzIfWweX3er1f5uNpGDygfQVQ==
|
||||
|
||||
"@next/swc-win32-ia32-msvc@14.2.22":
|
||||
version "14.2.22"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.22.tgz#70d8d5a48e78c7382c3e0544af28c2788ca6b551"
|
||||
integrity sha512-5IhDDTPEbzPR31ZzqHe90LnNe7BlJUZvC4sA1thPJV6oN5WmtWjZ0bOYfNsyZx00FJt7gggNs6SrsX0UEIcIpA==
|
||||
"@next/swc-win32-ia32-msvc@14.2.21":
|
||||
version "14.2.21"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.21.tgz#c959135a78cab18cca588d11d1e33bcf199590d4"
|
||||
integrity sha512-w5bacz4Vxqrh06BjWgua3Yf7EMDb8iMcVhNrNx8KnJXt8t+Uu0Zg4JHLDL/T7DkTCEEfKXO/Er1fcfWxn2xfPA==
|
||||
|
||||
"@next/swc-win32-x64-msvc@14.2.22":
|
||||
version "14.2.22"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.22.tgz#b034f544c1346093a235f6bba46497a1ba344fc1"
|
||||
integrity sha512-nvRaB1PyG4scn9/qNzlkwEwLzuoPH3Gjp7Q/pLuwUgOTt1oPMlnCI3A3rgkt+eZnU71emOiEv/mR201HoURPGg==
|
||||
"@next/swc-win32-x64-msvc@14.2.21":
|
||||
version "14.2.21"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.21.tgz#21ff892286555b90538a7d1b505ea21a005d6ead"
|
||||
integrity sha512-sT6+llIkzpsexGYZq8cjjthRyRGe5cJVhqh12FmlbxHqna6zsDDK8UNaV7g41T6atFHCJUPeLb3uyAwrBwy0NA==
|
||||
|
||||
"@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3":
|
||||
version "2.1.8-no-fsevents.3"
|
||||
@@ -3815,181 +3815,181 @@
|
||||
resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.5.2.tgz#db7257d727c891905947bd1c1a99da20e03c2ebd"
|
||||
integrity sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==
|
||||
|
||||
"@tiptap/core@^2.1.13", "@tiptap/core@^2.11.0", "@tiptap/core@^2.4.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.11.0.tgz#72891ae9b3e4b2a67f79ab3bcb14483d30a9bd8a"
|
||||
integrity sha512-0S3AWx6E2QqwdQqb6z0/q6zq2u9lA9oL3BLyAaITGSC9zt8OwjloS2k1zN6wLa9hp2rO0c0vDnWsTPeFaEaMdw==
|
||||
"@tiptap/core@^2.1.13", "@tiptap/core@^2.10.4", "@tiptap/core@^2.4.0":
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.10.4.tgz#0b3ad822d71f5834b281590809f430e6fd41523c"
|
||||
integrity sha512-fExFRTRgb6MSpg2VvR5qO2dPTQAZWuUoU4UsBCurIVcPWcyVv4FG1YzgMyoLDKy44rebFtwUGJbfU9NzX7Q/bA==
|
||||
|
||||
"@tiptap/extension-blockquote@^2.1.13", "@tiptap/extension-blockquote@^2.11.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.11.0.tgz#c80aec1ce7791be5a0b45071ffb7481f40c35666"
|
||||
integrity sha512-DBjWbgmbAAR879WAsk0+5xxgqpOTweWNnY7kEqWv3EJtLUvECXN63smiv3o4fREwwbEJqgihBu5/YugRC5z1dg==
|
||||
"@tiptap/extension-blockquote@^2.1.13", "@tiptap/extension-blockquote@^2.10.4":
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.10.4.tgz#0f9a26740009fc7430fabc423077c369feaebb42"
|
||||
integrity sha512-4JSwAM3B92YWvGzu/Vd5rovPrCGwLSaSLD5rxcLyfxLSrTDQd3n7lp78pzVgGhunVECzaGF5A0ByWWpEyS0a3w==
|
||||
|
||||
"@tiptap/extension-bold@^2.11.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.11.0.tgz#170e04df4396f3a3b830e34055b3a87f4e42a3b6"
|
||||
integrity sha512-3x9BQZHYD5xFA0pCEneEMHZyIoxYo4NKcbhR4CLxGad1Xd+5g109nr1+eZ1JgvnChkeVf1eD6SaQE2A28lxR5g==
|
||||
"@tiptap/extension-bold@^2.10.4":
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.10.4.tgz#ac4a791fe9c4ccf0c4fb70c304e663cc07ba9397"
|
||||
integrity sha512-SdO4oFQKaERCGfwOc1CLYQRtThENam2KWfWmvpsymknokt5qYzU57ft0SE1HQV9vVYEzZ9HrWIgv2xrgu0g9kg==
|
||||
|
||||
"@tiptap/extension-bubble-menu@^2.11.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.11.0.tgz#f2f596d01d24312962bd9c14a1c1a797931cf221"
|
||||
integrity sha512-21KyB7+QSQjw72Oxzs3Duw9WErAUrigFZCyoCZNjp24wP7mFVsy1jAcnRiAi8pBVwlwHBZ29IW1PeavqCSFFVA==
|
||||
"@tiptap/extension-bubble-menu@^2.10.4":
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.10.4.tgz#6d2611fd3dd4c6b848b5f028ba96567aec5bd1e3"
|
||||
integrity sha512-GVtZwJaQyLBptMsmDtYl5GEobd1Uu7C9sc9Z+PdXwMuxmFfg+j07bCKCj5JJj/tjgXCSLVxWdTlDHxNrgzQHjw==
|
||||
dependencies:
|
||||
tippy.js "^6.3.7"
|
||||
|
||||
"@tiptap/extension-bullet-list@^2.11.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.11.0.tgz#972f31f1fffc74327c3cb9795893c13736132de3"
|
||||
integrity sha512-UALypJvO+cPSk/nC1HhkX/ImS9FxbKe2Pr0iDofakvZU1U1msumLVn2M/iq+ax1Mm9thodpvJv0hGDtFRwm7lQ==
|
||||
"@tiptap/extension-bullet-list@^2.10.4":
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.10.4.tgz#0b86fb2782b4a7fc012a23d3e265bcc798e70a12"
|
||||
integrity sha512-JVwDPgOBYRU2ivaadOh4IaQYXQEiSw6sB36KT/bwqJF2GnEvLiMwptdRMn9Uuh6xYR3imjIZtV6uZAoneZdd6g==
|
||||
|
||||
"@tiptap/extension-character-count@^2.6.5":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-character-count/-/extension-character-count-2.11.0.tgz#7d3992ceba72f1eeb2db3a1fc997c50dddd7cf8c"
|
||||
integrity sha512-WbqVr1QY62vxpmDJP5k3bwyzoHha1sZTs0xj3L+4s1j/SB2A7tAlFdcNPPwfbPOINHQgomSAyClfTyd4Gor7HA==
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-character-count/-/extension-character-count-2.10.4.tgz#dccf731a48eaf93075500709929a1bf0eff1d8f9"
|
||||
integrity sha512-NoVLQI/zTEdA0EZe5+oinQ+F/WQMblZRdEWgfsUtQoLRloSAF+pFeQwDenpejdOuWqixT4vdzpboBocj4uQLsw==
|
||||
|
||||
"@tiptap/extension-code-block@^2.11.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.11.0.tgz#ab8d19bb85ba9dccb14ad5dcc6559cb7965d173e"
|
||||
integrity sha512-8of3qTOLjpveHBrrk8KVliSUVd6R2i2TNrBj0f/21HcFVAy0fP++02p6vI6UPOhwM3+p3CprGdSM48DFCu1rqw==
|
||||
"@tiptap/extension-code-block@^2.10.4":
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.10.4.tgz#a86a4477acc995c5185e32dd60188f4e173f9341"
|
||||
integrity sha512-qS4jnbJqghNMT2+B+GQ807ATgqkL9OQ//NlL+ZwVSe+DPDduNA9B6IB9SrWENDfOnzekpi7kcEcm+RenELARRQ==
|
||||
|
||||
"@tiptap/extension-code@^2.11.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.11.0.tgz#eaf3a0a63ceeda462d1526e40a221223c7497b54"
|
||||
integrity sha512-2roNZxcny1bGjyZ8x6VmGTuKbwfJyTZ1hiqPc/CRTQ1u42yOhbjF4ziA5kfyUoQlzygZrWH9LR5IMYGzPQ1N3w==
|
||||
"@tiptap/extension-code@^2.10.4":
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.10.4.tgz#d6d1fd9e7f1b457700b6c47e115fb1cc9b9039f8"
|
||||
integrity sha512-Vj/N0nbSQiV1o7X7pRySK9Fu72Dd266gm27TSlsts6IwJu5MklFvz7ezJUWoLjt2wmCV8/U/USmk/39ic9qjvg==
|
||||
|
||||
"@tiptap/extension-collaboration-cursor@^2.6.6":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-collaboration-cursor/-/extension-collaboration-cursor-2.11.0.tgz#14f60c6d7774aa104dbc8b137320638a05ce0110"
|
||||
integrity sha512-JZx9SWOxEYQIGaJKndsCPdQas8hniodSsfAFjJq1X62nl7Hlif//mrjAU8c5gRCd7KtTxf/Q8Y7cClLdfkjQmQ==
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-collaboration-cursor/-/extension-collaboration-cursor-2.10.4.tgz#2d6f177d5ffbdef40af3863e22466d811d6fe0ba"
|
||||
integrity sha512-U5FJnvIveqLxKZ9aLPgXj1EDzfFfLlHX6J6VZNGAc0QsK5rWCdiU7HWuG2hNTSjHayqh/2V+x30PTMc5EuCadg==
|
||||
|
||||
"@tiptap/extension-collaboration@^2.3.2":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-collaboration/-/extension-collaboration-2.11.0.tgz#21ac1c8bc2ca6d8ba2a838e63457528627294888"
|
||||
integrity sha512-pS3E//ODD80PwVXp7zOqek0q9z5AtZ6sMSK5nPneNioe7dSvCeQzToOD9V6EevK4KChUIN9wEryK8mkQs57ioA==
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-collaboration/-/extension-collaboration-2.10.4.tgz#7764d430f6a3c2e1cca7d07ab6d4c140b322b322"
|
||||
integrity sha512-IvVK/KGG3A0r/Du9ISv06v0VkKXB81RbCK3b/FSkV8+GPQXOqJ9L3aQ4N1LO7ZX5Cb0RbfVgSMK8WH2MIl6xKQ==
|
||||
|
||||
"@tiptap/extension-document@^2.11.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.11.0.tgz#dcae7bc3a29b279ddbf88fc2b248817705ccb8a6"
|
||||
integrity sha512-9YI0AT3mxyUZD7NHECHyV1uAjQ8KwxOS5ACwvrK1MU8TqY084LmodYNTXPKwpqbr51yvt3qZq1R7UIVu4/22Cg==
|
||||
"@tiptap/extension-document@^2.10.4":
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.10.4.tgz#68575c122f6d71556dae6f9df6173903b7cdfdf9"
|
||||
integrity sha512-1Pqrl6Rr9bVEHJ3zO2dM7UUA0Qn/r70JQ9YLlestjW1sbMaMuY3Ifvu2uSyUE7SAGV3gvxwNVQCrv8f0VlVEaA==
|
||||
|
||||
"@tiptap/extension-dropcursor@^2.11.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.11.0.tgz#c81eea3f90c460d1eefed14f8e9735346340191b"
|
||||
integrity sha512-p7tUtlz7KzBa+06+7W2LJ8AEiHG5chdnUIapojZ7SqQCrFRVw70R+orpkzkoictxNNHsun0A9FCUy4rz8L0+nQ==
|
||||
"@tiptap/extension-dropcursor@^2.10.4":
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.10.4.tgz#6dea1c17878a8a0d68c7915f34b7b02980e91c90"
|
||||
integrity sha512-0XEM/yNLaMc/sZlYOau7XpHyYiHT9LwXUe7kmze/L8eowIa/iLvmRbcnUd3rtlZ7x7wooE6UO9c7OtlREg4ZBw==
|
||||
|
||||
"@tiptap/extension-floating-menu@^2.11.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.11.0.tgz#fa96fc2a75d94d2e21f4a6ed6b9fedd53d344a4a"
|
||||
integrity sha512-dexhhUJm0x9OolbeVCa7RpxuALU3bJZC7dFpu/rPG3ZetXKhVw8hTrqUQD5w1DjXpczBzScnLgLrvnjxbG66pw==
|
||||
"@tiptap/extension-floating-menu@^2.10.4":
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.10.4.tgz#e00bbeba8b67ce2511464b9b5203a399fc7b4311"
|
||||
integrity sha512-K2MDiu6CwQ7+Jr6g1Lh3Tuxm1L6SefSHMpQO0UW3aRGwgEV5pjlrztnBFX4K9b7MNuQ4dJGCUK9u8Cv7Xss0qg==
|
||||
dependencies:
|
||||
tippy.js "^6.3.7"
|
||||
|
||||
"@tiptap/extension-gapcursor@^2.11.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.11.0.tgz#01511c996656c43ed008825b66ccdf9fa365a674"
|
||||
integrity sha512-1TVOthPkUYwTQnQwP0BzuIHVz09epOiXJQ3GqgNZsmTehwcMzz2vGCpx1JXhZ5DoMaREHNLCdraXb1n2FdhDNA==
|
||||
"@tiptap/extension-gapcursor@^2.10.4":
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.10.4.tgz#697f0f599c5fe90f584e3f94e4866959211c8688"
|
||||
integrity sha512-KbJfoaqTZePpkWAN+klpK5j0UVtELxN7H5B0J556/UCB/rnq+OsdEFHPks2Ss9TidqWzRUqcxUE50UZ7b8h7Ug==
|
||||
|
||||
"@tiptap/extension-hard-break@^2.11.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.11.0.tgz#0e199a1c58171fe1879e730b87666e759fe55c04"
|
||||
integrity sha512-7pMgPNk2FnPT0LcWaWNNxOLK3LQnRSYFgrdBGMXec3sy+y3Lit3hM+EZhbZcHpTIQTbWWs+eskh1waRMIt0ZaQ==
|
||||
"@tiptap/extension-hard-break@^2.10.4":
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.10.4.tgz#57767f35950405c457789faa7b793830860096cc"
|
||||
integrity sha512-nW9wubW1A/CO2Ssn9wNMP08tR9Oarg9VUGzJ5qNuz38DDNyntE1SyDS+XStkeMq5nKqJ3YKhukyAJH/PiRq4Mg==
|
||||
|
||||
"@tiptap/extension-heading@^2.11.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.11.0.tgz#8b7530a325faffdf325d03d82a2d6947a440d662"
|
||||
integrity sha512-vrYvxibsY7/Sd2wYQDZ8AfIORfFi/UHZAWI7JmaMtDkILuMLYQ+jXb7p4K2FFW/1nN7C8QqgLLFI5AfjZUusgw==
|
||||
"@tiptap/extension-heading@^2.10.4":
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.10.4.tgz#6df708f74f2f2d0716f6e3d32100c29c8be3fe68"
|
||||
integrity sha512-7D0h0MIvE97Gx3Qwuo2xnPDK07WfCnyh4tpOPBOus4e1g6sgxVkwDwhbkYWiwvIrf4BUVJflnke/DEDCVp6/Eg==
|
||||
|
||||
"@tiptap/extension-history@^2.11.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.11.0.tgz#fc04cb418e4bad6c659b101d48812e43f04c3bbc"
|
||||
integrity sha512-eEUEDoOtS17AHVEPbGfZ+x2L5A87SiIsppWYTkpfIH/8EnVQmzu+3i1tcT9cWvHC31d9JTG7TDptVuuHr30TJw==
|
||||
"@tiptap/extension-history@^2.10.4":
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.10.4.tgz#58e1b819149354538526475896a9904e954d02a6"
|
||||
integrity sha512-fg6BNxbpMMtgKaiNI/GLcCzkxIQMwSYBhO9LA0CxLvmsWGU+My4r9W3DK6HwNoRJ9+6OleDPSLo1P73fbSTtEA==
|
||||
|
||||
"@tiptap/extension-horizontal-rule@^2.11.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.11.0.tgz#ba7dc213f93cf3920ebcff246a8aaf845cb0b683"
|
||||
integrity sha512-ZbkILwmcccmwQB2VTA/dzHRMB+xoJQ8UJdafcUiaAUlQfvDgl898+AYMa2GRTZkLPvzCKjXMC9hybSyy54Lz3Q==
|
||||
"@tiptap/extension-horizontal-rule@^2.10.4":
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.10.4.tgz#a2099c156c4c691f4951def225e1102ad1f69f22"
|
||||
integrity sha512-s9ycm/BOGoW3L0Epnj541vdngHbFbMM488HoODd1CmVSw1C+wBWFgsukgqKjlyE3VGfZXuSb1ur9zinW0RiLJQ==
|
||||
|
||||
"@tiptap/extension-image@^2.1.13":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.11.0.tgz#e9611a6a032804279f9b12a483a7afe696358a3f"
|
||||
integrity sha512-R+JkK5ocX35ag1c42aAw6rcb9QlLUBB0ju8A7b+8qZXN5yWKE0yO/oixYFmnZN7WSnBYtzuCVDX8cvRG+BPbgA==
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.10.4.tgz#577a0e9b92be845b91165d29136327c951bb967e"
|
||||
integrity sha512-fPdAqP4M1zwz5jyrQNIEL4OvvGeJso45svaaBLV342yRLOpbVIgAp/RsuWSGDQTUWoGhdkHdIrbH2bUGNEbMBg==
|
||||
|
||||
"@tiptap/extension-italic@^2.11.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.11.0.tgz#fe36d1aac51d8d5f8c276116a1e4408396440d8e"
|
||||
integrity sha512-T+jjS0gOsvNzQXVTSArmUp/kt2R9OikPQaV1DI60bfjO0rknOgtG0tbwZmfbugzwc07RbpxOYFy3vBxMLDsksA==
|
||||
"@tiptap/extension-italic@^2.10.4":
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.10.4.tgz#000cd53a5d54efe1c8bfa51a2bd6003268dcd01d"
|
||||
integrity sha512-8MIQ+wsbyxNCZDCFTVTOXrS2AvFyOhtlBNgVU2+6r6xnJV4AcfEA3qclysqrjOlL117ped/nzDeoB0AeX0CI+Q==
|
||||
|
||||
"@tiptap/extension-list-item@^2.1.13", "@tiptap/extension-list-item@^2.11.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.11.0.tgz#15889fd8217b998bfef78cd9079c8405b5a9abcd"
|
||||
integrity sha512-Jikcg0fccpM13a3hAFLtguMcpVg4eMWI8NnC0aUULD9rFhvWZQYQYQuoK3fO6vQrAQpNhsV4oa0dfSq1btu9kg==
|
||||
"@tiptap/extension-list-item@^2.1.13", "@tiptap/extension-list-item@^2.10.4":
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.10.4.tgz#3ea8e597567d448b00ac4d7b0ef9d1b91bc1d306"
|
||||
integrity sha512-8K3WUD5fPyw2poQKnJGGm7zlfeIbpld92+SRF4M9wkp95EzvgexTlodvxlrL3i8zKXcQQVyExWA8kCcGPFb9bA==
|
||||
|
||||
"@tiptap/extension-mention@^2.1.13":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-mention/-/extension-mention-2.11.0.tgz#515f831975188ce33e3c0951f94a34396a3f35cd"
|
||||
integrity sha512-5/Yk2rTpsoIZaNyo4f+CgsCCkQkSiNAp24HOvvCm9Dp9w1gIFm6y6dSj5RYqzEucGjOkoaBbfMcm1QxKWIj6/A==
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-mention/-/extension-mention-2.10.4.tgz#a01856024f948daf2e1f9ed820059f1bdb15ff73"
|
||||
integrity sha512-pVouKWxSVQSy4zn6HrljPIP1AG826gkm/w18Asi8QnZvR0AMqGLh9q7qd9Kc0j8NKoCzlzK8hECGlYPEaBldow==
|
||||
|
||||
"@tiptap/extension-ordered-list@^2.11.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.11.0.tgz#29d4afab66e85c701a7ab5b86ea1cc1f5ae7e3c7"
|
||||
integrity sha512-i6pNsDHA2QvBAebwjAuvhHKwz+bZVJ929PCIJaN8mxg0ldiAmFbAsf+rwIIFHWogMp+5xEX2RBzux20usNVZ9w==
|
||||
"@tiptap/extension-ordered-list@^2.10.4":
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.10.4.tgz#3da20e5087329a9999837b5860954bd14b14ef60"
|
||||
integrity sha512-NaeEu+qFG2O0emc8WlwOM7DKNKOaqHWuNkuKrrmQzslgL+UQSEGlGMo6NEJ5sLLckPBDpIa0MuRm30407JE+cg==
|
||||
|
||||
"@tiptap/extension-paragraph@^2.11.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.11.0.tgz#936bfbc6781acd5ac0dba6bcdc2fa67514ce6164"
|
||||
integrity sha512-xLNC05An3SQq0bVHJtOTLa8As5r6NxDZFpK0NZqO2hTq/fAIRL/9VPeZ8E0tziXULwIvIPp+L0Taw3TvaUkRUg==
|
||||
"@tiptap/extension-paragraph@^2.10.4":
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.10.4.tgz#e2c94eaee7c69b7c38f98abd50927a8a6811dc49"
|
||||
integrity sha512-SRNVhT8OXqjpZtcyuOtofbtOpXXFrQrjqqCc/yXebda//2SfUTOvB16Lss77vQOWi6xr7TF1mZuowJgSTkcczw==
|
||||
|
||||
"@tiptap/extension-placeholder@^2.3.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.11.0.tgz#a330df0bc791df82b3a84490031a8db9a68f4061"
|
||||
integrity sha512-ee8vz51pW6H+1rEDMFg2FnBs2Tj5rUHlJ1JgD7Dcp3+89SVHGB3UILGfbNpAnHZvhmsTY3NcfPAcZZ80QfQFMQ==
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.10.4.tgz#706e30941e3232894db647ab4254e8ba65f54920"
|
||||
integrity sha512-leWG4xP7cvddR6alGZS7yojOh9941bxehgAeQDLlEisaJcNa2Od5Vbap2zipjc5sXMxZakQVChL27oH1wWhHkQ==
|
||||
|
||||
"@tiptap/extension-strike@^2.11.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.11.0.tgz#8507cfb501f4950d869f8ddd1adb47b66680765f"
|
||||
integrity sha512-71i2IZT58kY2ohlhyO+ucyAioNNCkNkuPkrVERc9lXhmcCKOff5y6ekDHQHO2jNjnejkVE5ibyDO3Z7RUXjh1A==
|
||||
"@tiptap/extension-strike@^2.10.4":
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.10.4.tgz#8c450d1cb26f6cb0b79403aed2bf0bd6d1d0cd98"
|
||||
integrity sha512-OibipsomFpOJWTPVX/z4Z53HgwDA93lE/loHGa+ONJfML1dO6Zd6UTwzaVO1/g8WOwRgwkYu/6JnhxLKRlP8Lg==
|
||||
|
||||
"@tiptap/extension-task-item@^2.1.13":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-task-item/-/extension-task-item-2.11.0.tgz#ff97f10bf39d6c27fd3f3f1ee3987d7015304c11"
|
||||
integrity sha512-qu6VuRc8qF80Bwr82CItFcrKtC67LJkwpxESLEIi42zWZ5sXF/3DJEPPS/4Kk+nAc9UCBoEMFAULibPq7rRl/w==
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-task-item/-/extension-task-item-2.10.4.tgz#afc59e1632db1d7d1d8c2ff4e897a638337a949f"
|
||||
integrity sha512-ucKGXdHdHCBanIJTB/nhmQ3iIL6BcSVKr7mN5BGEu6sSLYROflX7lmnMPVIRcTKJz+FGJeR6AqPFVagZAXVkGQ==
|
||||
|
||||
"@tiptap/extension-task-list@^2.1.13":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-task-list/-/extension-task-list-2.11.0.tgz#2f197a70aafc0c23163ed70aa314cc0300534cf6"
|
||||
integrity sha512-+dZRjeXLXxyliFt3J7uQADxfOwi6ntyepVM+ri1rnmIaqVZUHJbUFodOc0LivI+Z5iZZ10u3TId8gehqWJHD+w==
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-task-list/-/extension-task-list-2.10.4.tgz#4c22d70a3d7147ef5919d368ee619dc94654df16"
|
||||
integrity sha512-21bFlHlvGr5hsXUEug9p+BWPLqdziFS/4mGG6nUnrSDI1e4eEC86WZczsG+If6FEpjcCS9Eb2RHgqaA4VoJEqg==
|
||||
|
||||
"@tiptap/extension-text-align@^2.8.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-text-align/-/extension-text-align-2.11.0.tgz#b90b86ee3f6e14c9abf186cb8ab6ced20c0df14d"
|
||||
integrity sha512-VRXBqO17po6ddqhoWLBa2aCX/tqHdzdKPLfjnBy1fF8hjQKbidzjMWhb4CMm31ApvJjKK/DTkM3EnyYS/XDhng==
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-text-align/-/extension-text-align-2.10.4.tgz#ffd9cd61bf7f00c6ed4b3b5f377a7d5bed56550b"
|
||||
integrity sha512-rt2Hz3N081QAgkKKSMpyDZTKorBmXKpeHkYIw+ArVuvBYhi8x5wVyZgZ2SIMW9A5G4rx1M0czn7xNi+/P3NopQ==
|
||||
|
||||
"@tiptap/extension-text-style@^2.11.0", "@tiptap/extension-text-style@^2.7.1":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-text-style/-/extension-text-style-2.11.0.tgz#2acb6207fe6acdb5479384682846980be15caa80"
|
||||
integrity sha512-vuA16wMZ6J3fboL7FObwV2f5uN9Vg0WYmqU7971vxzJyaRj9VE1eeH8Kh5fq4RgwDzc13MZGvZZV4HcE1R8o8A==
|
||||
"@tiptap/extension-text-style@^2.10.4", "@tiptap/extension-text-style@^2.7.1":
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-text-style/-/extension-text-style-2.10.4.tgz#07af922c266fef7da13cc83befbbd5da512b7402"
|
||||
integrity sha512-ibq7avkcwHyUSG53Hf+P31rrwsKVbbiqbWZM4kXC7M2X3iUwFrtvaa+SWzyWQfE1jl2cCrD1+rfSkj/alcOKGg==
|
||||
|
||||
"@tiptap/extension-text@^2.11.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.11.0.tgz#56ad3d9b14a34f67f7f8b82a499ef7a9a10ef0a6"
|
||||
integrity sha512-LcyrP+7ZEVx3YaKzjMAeujq+4xRt4mZ3ITGph2CQ4vOKFaMI8bzSR909q18t7Qyyvek0a9VydEU1NHSaq4G5jw==
|
||||
"@tiptap/extension-text@^2.10.4":
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.10.4.tgz#ca5c7618ec122cfd72399b8c593023cf4a5829d5"
|
||||
integrity sha512-wPdVxCHrIS9S+8n08lgyyqRZPj9FBbyLlFt74/lV5yBC3LOorq1VKdjrTskmaj4jud7ImXoKDyBddAYTHdJ1xw==
|
||||
|
||||
"@tiptap/extension-underline@^2.1.13":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-2.11.0.tgz#473025d3ed01953fb2c23f8060ea90be4c231faa"
|
||||
integrity sha512-DE1piq441y1+9Aj1pvvuq1dcc5B2HZ2d1SPtO4DTMjCxrhok12biTkMxxq0q1dzA5/BouLlUW6WTPpinhmrUWA==
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-2.10.4.tgz#5892a3dc7997818c0bbc0dde4e48b036d6786975"
|
||||
integrity sha512-KhlCndQFMe/Gsz+3qkVn9z1utDy8y1igvdePijMjA5B8PTu0hPs2Q1d6szfLTBdtoFNkCokknxzXhSY0OFJEyQ==
|
||||
|
||||
"@tiptap/html@^2.3.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/html/-/html-2.11.0.tgz#dd0b4195a07bbdca27aa13325b8ebac41480a6a0"
|
||||
integrity sha512-9+8eSeey3gm6vMtbt+uKZfkvtwsWr577lhtTeGUsoThim9zyBnbhzHc1dQw2m1RefOoPcODrnnQPvi5nvA84Cw==
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/html/-/html-2.10.4.tgz#f4cf5b93a9e5d47538c9935912006e51bbb513dc"
|
||||
integrity sha512-s9gWJy2Z+mfG5s8ewodv6d/iZq3bcc6osT9zsIvQcfoHh4j6Nq/DcIuZ/7AodgRFGZrIAEu4X1U4K2/Fk+gplA==
|
||||
dependencies:
|
||||
zeed-dom "^0.15.1"
|
||||
|
||||
"@tiptap/pm@^2.1.13", "@tiptap/pm@^2.11.0":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-2.11.0.tgz#c2ccb0c9b99fd5915d9390e90d3ab9e5fb408cd8"
|
||||
integrity sha512-4RU6bpODkMY+ZshzdRFcuUc5jWlMW82LWXR6UOsHK/X/Mav41ZFS0Cyf+hQM6gxxTB09YFIICmGpEpULb+/CuA==
|
||||
"@tiptap/pm@^2.1.13", "@tiptap/pm@^2.10.4":
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-2.10.4.tgz#28909a528a3ac59e4f62055d5b9b2890f6f386fc"
|
||||
integrity sha512-pZ4NEkRtYoDLe0spARvXZ1N3hNv/5u6vfPdPtEbmNpoOSjSNqDC1kVM+qJY0iaCYpxbxcv7cxn3kBumcFLQpJQ==
|
||||
dependencies:
|
||||
prosemirror-changeset "^2.2.1"
|
||||
prosemirror-collab "^1.3.1"
|
||||
@@ -4011,47 +4011,47 @@
|
||||
prosemirror-view "^1.37.0"
|
||||
|
||||
"@tiptap/react@^2.1.13":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/react/-/react-2.11.0.tgz#28b9ca64bdeb6302eaca1941ef792e3acea2e40e"
|
||||
integrity sha512-AALzHbqNq/gerJpkbXmN2OXFmHAs2bQENH7rXbnH70bpxVdIfQVtvjK4dIb+cQQvAuTWZvhsISnTrFY2BesT3Q==
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/react/-/react-2.10.4.tgz#cdd898ff2f962ecd7be593606507f95b90fab2f8"
|
||||
integrity sha512-JTeqDB+xgjo46QC9ILRXe2TcSfxKVRwhZ3vDvYoemN7giRk5a/WsCF1VQIT1fax+tCl6kfv3U1f4Mkx0DkbPkA==
|
||||
dependencies:
|
||||
"@tiptap/extension-bubble-menu" "^2.11.0"
|
||||
"@tiptap/extension-floating-menu" "^2.11.0"
|
||||
"@tiptap/extension-bubble-menu" "^2.10.4"
|
||||
"@tiptap/extension-floating-menu" "^2.10.4"
|
||||
"@types/use-sync-external-store" "^0.0.6"
|
||||
fast-deep-equal "^3"
|
||||
use-sync-external-store "^1"
|
||||
|
||||
"@tiptap/starter-kit@^2.1.13":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-2.11.0.tgz#3b4a9ca9daaffed3abd030d4cd72e8d9d3eb0649"
|
||||
integrity sha512-lrYmkeaAFiuUjN5nGnCowdjponrsR7eRmeTf/15/5oZsNrMN7t/fvPb014AqhG/anNasa0ism4CKZns3D+4pKQ==
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-2.10.4.tgz#37f95fae7ea36b29825720706c49dd0533274b0b"
|
||||
integrity sha512-tu/WCs9Mkr5Nt8c3/uC4VvAbQlVX0OY7ygcqdzHGUeG9zP3twdW7o5xM3kyDKR2++sbVzqu5Ll5qNU+1JZvPGQ==
|
||||
dependencies:
|
||||
"@tiptap/core" "^2.11.0"
|
||||
"@tiptap/extension-blockquote" "^2.11.0"
|
||||
"@tiptap/extension-bold" "^2.11.0"
|
||||
"@tiptap/extension-bullet-list" "^2.11.0"
|
||||
"@tiptap/extension-code" "^2.11.0"
|
||||
"@tiptap/extension-code-block" "^2.11.0"
|
||||
"@tiptap/extension-document" "^2.11.0"
|
||||
"@tiptap/extension-dropcursor" "^2.11.0"
|
||||
"@tiptap/extension-gapcursor" "^2.11.0"
|
||||
"@tiptap/extension-hard-break" "^2.11.0"
|
||||
"@tiptap/extension-heading" "^2.11.0"
|
||||
"@tiptap/extension-history" "^2.11.0"
|
||||
"@tiptap/extension-horizontal-rule" "^2.11.0"
|
||||
"@tiptap/extension-italic" "^2.11.0"
|
||||
"@tiptap/extension-list-item" "^2.11.0"
|
||||
"@tiptap/extension-ordered-list" "^2.11.0"
|
||||
"@tiptap/extension-paragraph" "^2.11.0"
|
||||
"@tiptap/extension-strike" "^2.11.0"
|
||||
"@tiptap/extension-text" "^2.11.0"
|
||||
"@tiptap/extension-text-style" "^2.11.0"
|
||||
"@tiptap/pm" "^2.11.0"
|
||||
"@tiptap/core" "^2.10.4"
|
||||
"@tiptap/extension-blockquote" "^2.10.4"
|
||||
"@tiptap/extension-bold" "^2.10.4"
|
||||
"@tiptap/extension-bullet-list" "^2.10.4"
|
||||
"@tiptap/extension-code" "^2.10.4"
|
||||
"@tiptap/extension-code-block" "^2.10.4"
|
||||
"@tiptap/extension-document" "^2.10.4"
|
||||
"@tiptap/extension-dropcursor" "^2.10.4"
|
||||
"@tiptap/extension-gapcursor" "^2.10.4"
|
||||
"@tiptap/extension-hard-break" "^2.10.4"
|
||||
"@tiptap/extension-heading" "^2.10.4"
|
||||
"@tiptap/extension-history" "^2.10.4"
|
||||
"@tiptap/extension-horizontal-rule" "^2.10.4"
|
||||
"@tiptap/extension-italic" "^2.10.4"
|
||||
"@tiptap/extension-list-item" "^2.10.4"
|
||||
"@tiptap/extension-ordered-list" "^2.10.4"
|
||||
"@tiptap/extension-paragraph" "^2.10.4"
|
||||
"@tiptap/extension-strike" "^2.10.4"
|
||||
"@tiptap/extension-text" "^2.10.4"
|
||||
"@tiptap/extension-text-style" "^2.10.4"
|
||||
"@tiptap/pm" "^2.10.4"
|
||||
|
||||
"@tiptap/suggestion@^2.0.13":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/suggestion/-/suggestion-2.11.0.tgz#826140c6f1a76af2d91713dafb4b142c803eabef"
|
||||
integrity sha512-f+KcczhzEEy2f7/0N/RSID+Z6NjxCX6ab26NLfWZxdaEm/J+vQ2Pqh/e5Z59vMfKiC0DJXVcO0rdv2LBh23qDw==
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/suggestion/-/suggestion-2.10.4.tgz#732320b65bc55bcc2a33a8f32072f9478ffb7436"
|
||||
integrity sha512-7Bzcn1REA7OmVRxiMF2kVK9EhosXotdLAGaEvSbn4zQtHCJG0tREuYvPy53LGzVuPkBDR6Pf6sp1QbGvSne/8g==
|
||||
|
||||
"@todesktop/client-core@^1.12.4":
|
||||
version "1.12.4"
|
||||
@@ -4731,15 +4731,15 @@
|
||||
integrity sha512-FZJgC5Bxuqg7Rhsm/bx6gAruHHhDQ55r+s0JhDh8CQ16fD7NsJJ+p8YMMQDhSQoIrSmjpqqYWA96oQVMNkjRyA==
|
||||
|
||||
"@typescript-eslint/eslint-plugin@^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", "@typescript-eslint/eslint-plugin@^8.6.0":
|
||||
version "8.19.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.19.0.tgz#2b1e1b791e21d5fc27ddc93884db066444f597b5"
|
||||
integrity sha512-NggSaEZCdSrFddbctrVjkVZvFC6KGfKfNK0CU7mNK/iKHGKbzT4Wmgm08dKpcZECBu9f5FypndoMyRHkdqfT1Q==
|
||||
version "8.18.1"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.1.tgz#992e5ac1553ce20d0d46aa6eccd79dc36dedc805"
|
||||
integrity sha512-Ncvsq5CT3Gvh+uJG0Lwlho6suwDfUXH0HztslDf5I+F2wAFAZMRwYLEorumpKLzmO2suAXZ/td1tBg4NZIi9CQ==
|
||||
dependencies:
|
||||
"@eslint-community/regexpp" "^4.10.0"
|
||||
"@typescript-eslint/scope-manager" "8.19.0"
|
||||
"@typescript-eslint/type-utils" "8.19.0"
|
||||
"@typescript-eslint/utils" "8.19.0"
|
||||
"@typescript-eslint/visitor-keys" "8.19.0"
|
||||
"@typescript-eslint/scope-manager" "8.18.1"
|
||||
"@typescript-eslint/type-utils" "8.18.1"
|
||||
"@typescript-eslint/utils" "8.18.1"
|
||||
"@typescript-eslint/visitor-keys" "8.18.1"
|
||||
graphemer "^1.4.0"
|
||||
ignore "^5.3.1"
|
||||
natural-compare "^1.4.0"
|
||||
@@ -4762,14 +4762,14 @@
|
||||
tsutils "^3.21.0"
|
||||
|
||||
"@typescript-eslint/parser@^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", "@typescript-eslint/parser@^8.6.0":
|
||||
version "8.19.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.19.0.tgz#f1512e6e5c491b03aabb2718b95becde22b15292"
|
||||
integrity sha512-6M8taKyOETY1TKHp0x8ndycipTVgmp4xtg5QpEZzXxDhNvvHOJi5rLRkLr8SK3jTgD5l4fTlvBiRdfsuWydxBw==
|
||||
version "8.18.1"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.18.1.tgz#c258bae062778b7696793bc492249027a39dfb95"
|
||||
integrity sha512-rBnTWHCdbYM2lh7hjyXqxk70wvon3p2FyaniZuey5TrcGBpfhVp0OxOa6gxr9Q9YhZFKyfbEnxc24ZnVbbUkCA==
|
||||
dependencies:
|
||||
"@typescript-eslint/scope-manager" "8.19.0"
|
||||
"@typescript-eslint/types" "8.19.0"
|
||||
"@typescript-eslint/typescript-estree" "8.19.0"
|
||||
"@typescript-eslint/visitor-keys" "8.19.0"
|
||||
"@typescript-eslint/scope-manager" "8.18.1"
|
||||
"@typescript-eslint/types" "8.18.1"
|
||||
"@typescript-eslint/typescript-estree" "8.18.1"
|
||||
"@typescript-eslint/visitor-keys" "8.18.1"
|
||||
debug "^4.3.4"
|
||||
|
||||
"@typescript-eslint/scope-manager@5.62.0":
|
||||
@@ -4780,13 +4780,13 @@
|
||||
"@typescript-eslint/types" "5.62.0"
|
||||
"@typescript-eslint/visitor-keys" "5.62.0"
|
||||
|
||||
"@typescript-eslint/scope-manager@8.19.0":
|
||||
version "8.19.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.19.0.tgz#28fa413a334f70e8b506a968531e0a7c9c3076dc"
|
||||
integrity sha512-hkoJiKQS3GQ13TSMEiuNmSCvhz7ujyqD1x3ShbaETATHrck+9RaDdUbt+osXaUuns9OFwrDTTrjtwsU8gJyyRA==
|
||||
"@typescript-eslint/scope-manager@8.18.1":
|
||||
version "8.18.1"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.18.1.tgz#52cedc3a8178d7464a70beffed3203678648e55b"
|
||||
integrity sha512-HxfHo2b090M5s2+/9Z3gkBhI6xBH8OJCFjH9MhQ+nnoZqxU3wNxkLT+VWXWSFWc3UF3Z+CfPAyqdCTdoXtDPCQ==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.19.0"
|
||||
"@typescript-eslint/visitor-keys" "8.19.0"
|
||||
"@typescript-eslint/types" "8.18.1"
|
||||
"@typescript-eslint/visitor-keys" "8.18.1"
|
||||
|
||||
"@typescript-eslint/type-utils@5.62.0":
|
||||
version "5.62.0"
|
||||
@@ -4798,13 +4798,13 @@
|
||||
debug "^4.3.4"
|
||||
tsutils "^3.21.0"
|
||||
|
||||
"@typescript-eslint/type-utils@8.19.0":
|
||||
version "8.19.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.19.0.tgz#41abd7d2e4cf93b6854b1fe6cbf416fab5abf89f"
|
||||
integrity sha512-TZs0I0OSbd5Aza4qAMpp1cdCYVnER94IziudE3JU328YUHgWu9gwiwhag+fuLeJ2LkWLXI+F/182TbG+JaBdTg==
|
||||
"@typescript-eslint/type-utils@8.18.1":
|
||||
version "8.18.1"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.18.1.tgz#10f41285475c0bdee452b79ff7223f0e43a7781e"
|
||||
integrity sha512-jAhTdK/Qx2NJPNOTxXpMwlOiSymtR2j283TtPqXkKBdH8OAMmhiUfP0kJjc/qSE51Xrq02Gj9NY7MwK+UxVwHQ==
|
||||
dependencies:
|
||||
"@typescript-eslint/typescript-estree" "8.19.0"
|
||||
"@typescript-eslint/utils" "8.19.0"
|
||||
"@typescript-eslint/typescript-estree" "8.18.1"
|
||||
"@typescript-eslint/utils" "8.18.1"
|
||||
debug "^4.3.4"
|
||||
ts-api-utils "^1.3.0"
|
||||
|
||||
@@ -4813,10 +4813,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f"
|
||||
integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==
|
||||
|
||||
"@typescript-eslint/types@8.19.0":
|
||||
version "8.19.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.19.0.tgz#a190a25c5484a42b81eaad06989579fdeb478cbb"
|
||||
integrity sha512-8XQ4Ss7G9WX8oaYvD4OOLCjIQYgRQxO+qCiR2V2s2GxI9AUpo7riNwo6jDhKtTcaJjT8PY54j2Yb33kWtSJsmA==
|
||||
"@typescript-eslint/types@8.18.1":
|
||||
version "8.18.1"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.18.1.tgz#d7f4f94d0bba9ebd088de840266fcd45408a8fff"
|
||||
integrity sha512-7uoAUsCj66qdNQNpH2G8MyTFlgerum8ubf21s3TSM3XmKXuIn+H2Sifh/ES2nPOPiYSRJWAk0fDkW0APBWcpfw==
|
||||
|
||||
"@typescript-eslint/typescript-estree@5.62.0":
|
||||
version "5.62.0"
|
||||
@@ -4831,13 +4831,13 @@
|
||||
semver "^7.3.7"
|
||||
tsutils "^3.21.0"
|
||||
|
||||
"@typescript-eslint/typescript-estree@8.19.0":
|
||||
version "8.19.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.19.0.tgz#6b4f48f98ffad6597379951b115710f4d68c9ccb"
|
||||
integrity sha512-WW9PpDaLIFW9LCbucMSdYUuGeFUz1OkWYS/5fwZwTA+l2RwlWFdJvReQqMUMBw4yJWJOfqd7An9uwut2Oj8sLw==
|
||||
"@typescript-eslint/typescript-estree@8.18.1":
|
||||
version "8.18.1"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.1.tgz#2a86cd64b211a742f78dfa7e6f4860413475367e"
|
||||
integrity sha512-z8U21WI5txzl2XYOW7i9hJhxoKKNG1kcU4RzyNvKrdZDmbjkmLBo8bgeiOJmA06kizLI76/CCBAAGlTlEeUfyg==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.19.0"
|
||||
"@typescript-eslint/visitor-keys" "8.19.0"
|
||||
"@typescript-eslint/types" "8.18.1"
|
||||
"@typescript-eslint/visitor-keys" "8.18.1"
|
||||
debug "^4.3.4"
|
||||
fast-glob "^3.3.2"
|
||||
is-glob "^4.0.3"
|
||||
@@ -4859,15 +4859,15 @@
|
||||
eslint-scope "^5.1.1"
|
||||
semver "^7.3.7"
|
||||
|
||||
"@typescript-eslint/utils@8.19.0":
|
||||
version "8.19.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.19.0.tgz#33824310e1fccc17f27fbd1030fd8bbd9a674684"
|
||||
integrity sha512-PTBG+0oEMPH9jCZlfg07LCB2nYI0I317yyvXGfxnvGvw4SHIOuRnQ3kadyyXY6tGdChusIHIbM5zfIbp4M6tCg==
|
||||
"@typescript-eslint/utils@8.18.1":
|
||||
version "8.18.1"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.18.1.tgz#c4199ea23fc823c736e2c96fd07b1f7235fa92d5"
|
||||
integrity sha512-8vikiIj2ebrC4WRdcAdDcmnu9Q/MXXwg+STf40BVfT8exDqBCUPdypvzcUPxEqRGKg9ALagZ0UWcYCtn+4W2iQ==
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils" "^4.4.0"
|
||||
"@typescript-eslint/scope-manager" "8.19.0"
|
||||
"@typescript-eslint/types" "8.19.0"
|
||||
"@typescript-eslint/typescript-estree" "8.19.0"
|
||||
"@typescript-eslint/scope-manager" "8.18.1"
|
||||
"@typescript-eslint/types" "8.18.1"
|
||||
"@typescript-eslint/typescript-estree" "8.18.1"
|
||||
|
||||
"@typescript-eslint/visitor-keys@5.62.0":
|
||||
version "5.62.0"
|
||||
@@ -4877,12 +4877,12 @@
|
||||
"@typescript-eslint/types" "5.62.0"
|
||||
eslint-visitor-keys "^3.3.0"
|
||||
|
||||
"@typescript-eslint/visitor-keys@8.19.0":
|
||||
version "8.19.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.19.0.tgz#dc313f735e64c4979c9073f51ffcefb6d9be5c77"
|
||||
integrity sha512-mCFtBbFBJDCNCWUl5y6sZSCHXw1DEFEk3c/M3nRK2a4XUB8StGFtmcEMizdjKuBzB6e/smJAAWYug3VrdLMr1w==
|
||||
"@typescript-eslint/visitor-keys@8.18.1":
|
||||
version "8.18.1"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.1.tgz#344b4f6bc83f104f514676facf3129260df7610a"
|
||||
integrity sha512-Vj0WLm5/ZsD013YeUKn+K0y8p1M0jPpxOkKdbD1wB0ns53a5piVY02zjf072TblEweAbcYiFiPoSMF3kp+VhhQ==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.19.0"
|
||||
"@typescript-eslint/types" "8.18.1"
|
||||
eslint-visitor-keys "^4.2.0"
|
||||
|
||||
"@typescript/vfs@^1.5.0":
|
||||
@@ -6202,9 +6202,9 @@ concurrently@^9.0.1:
|
||||
yargs "^17.7.2"
|
||||
|
||||
consola@^3.2.3:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/consola/-/consola-3.3.3.tgz#0dd8a2314b0f7bf18a49064138ad685f3346543d"
|
||||
integrity sha512-Qil5KwghMzlqd51UXM0b6fyaGHtOC22scxrwrz4A2882LyUMwQjnvaedN1HAeXzphspQ6CpHkzMAWxBTUruDLg==
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/consola/-/consola-3.3.1.tgz#e60b4bfcd9e36cd766cc9afe2c93c14fe64c9356"
|
||||
integrity sha512-GyKnPG3/I+a4RtJxgHquJXWr70g9I3c4NT3dvqh0LPHQP2nZFQBOBszb7a5u/pGzqr40AKplQA6UxM1BSynSXg==
|
||||
|
||||
constant-case@^3.0.4:
|
||||
version "3.0.4"
|
||||
@@ -6963,9 +6963,9 @@ ejs@^3.1.10:
|
||||
jake "^10.8.5"
|
||||
|
||||
electron-to-chromium@^1.5.73:
|
||||
version "1.5.76"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.76.tgz#db20295c5061b68f07c8ea4dfcbd701485d94a3d"
|
||||
integrity sha512-CjVQyG7n7Sr+eBXE86HIulnL5N8xZY1sgmOPGuq/F0Rr0FJq63lg0kEtOIDfZBk44FnDLf6FUJ+dsJcuiUDdDQ==
|
||||
version "1.5.75"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.75.tgz#bba96eabf0e8ca36324679caa38b982800acc87d"
|
||||
integrity sha512-Lf3++DumRE/QmweGjU+ZcKqQ+3bKkU/qjaKYhIJKEOhgIO9Xs6IiAQFkfFoj+RhgDk4LUeNsLo6plExHqSyu6Q==
|
||||
|
||||
element-resize-detector@^1.1.9:
|
||||
version "1.2.4"
|
||||
@@ -7058,9 +7058,9 @@ error-ex@^1.3.1:
|
||||
is-arrayish "^0.2.1"
|
||||
|
||||
es-abstract@^1.17.5, es-abstract@^1.23.2, es-abstract@^1.23.3, es-abstract@^1.23.5, es-abstract@^1.23.6:
|
||||
version "1.23.8"
|
||||
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.8.tgz#99754723118355d82fcef9ce4c90ccbcd5d2a285"
|
||||
integrity sha512-lfab8IzDn6EpI1ibZakcgS6WsfEBiB+43cuJo+wgylx1xKXf+Sp+YR3vFuQwC/u3sxYwV8Cxe3B0DpVUu/WiJQ==
|
||||
version "1.23.7"
|
||||
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.7.tgz#36e3da46fdb0d2ae3b9df4235e3a3167c1605b36"
|
||||
integrity sha512-OygGC8kIcDhXX+6yAZRGLqwi2CmEXCbLQixeGUgYeR+Qwlppqmo7DIDr8XibtEBZp+fJcoYpoatp5qwLMEdcqQ==
|
||||
dependencies:
|
||||
array-buffer-byte-length "^1.0.2"
|
||||
arraybuffer.prototype.slice "^1.0.4"
|
||||
@@ -7097,10 +7097,8 @@ es-abstract@^1.17.5, es-abstract@^1.23.2, es-abstract@^1.23.3, es-abstract@^1.23
|
||||
object-inspect "^1.13.3"
|
||||
object-keys "^1.1.1"
|
||||
object.assign "^4.1.7"
|
||||
own-keys "^1.0.0"
|
||||
regexp.prototype.flags "^1.5.3"
|
||||
safe-array-concat "^1.1.3"
|
||||
safe-push-apply "^1.0.0"
|
||||
safe-regex-test "^1.1.0"
|
||||
string.prototype.trim "^1.2.10"
|
||||
string.prototype.trimend "^1.0.9"
|
||||
@@ -7297,11 +7295,11 @@ escape-string-regexp@^1.0.5:
|
||||
integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
|
||||
|
||||
eslint-config-next@^14.1.0:
|
||||
version "14.2.22"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-14.2.22.tgz#c33cb4d1fc54673c8df475d6bca9f1f0249c69fe"
|
||||
integrity sha512-4C26Xkqh5RWO9ieNOg7flfWsGiIfzblhXWQHUCa4wgswfjeFm4ku4M/Zc2IGBwA2BmrSn5kyJ8vt+JQg55g65Q==
|
||||
version "14.2.21"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-14.2.21.tgz#2bc6869d5c3ddc267143d41cb4a4a2bff8817e58"
|
||||
integrity sha512-bi1Mn6LxWdQod9qvOBuhBhN4ZpBYH5DuyDunbZt6lye3zlohJyM0T5/oFokRPNl2Mqt3/+uwHxr8XKOkPe852A==
|
||||
dependencies:
|
||||
"@next/eslint-plugin-next" "14.2.22"
|
||||
"@next/eslint-plugin-next" "14.2.21"
|
||||
"@rushstack/eslint-patch" "^1.3.3"
|
||||
"@typescript-eslint/eslint-plugin" "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
"@typescript-eslint/parser" "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
@@ -10040,11 +10038,11 @@ next-themes@^0.2.1:
|
||||
integrity sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==
|
||||
|
||||
next@^14.2.20:
|
||||
version "14.2.22"
|
||||
resolved "https://registry.yarnpkg.com/next/-/next-14.2.22.tgz#0cd664916ef4c725f31fa812d870348cffd0115b"
|
||||
integrity sha512-Ps2caobQ9hlEhscLPiPm3J3SYhfwfpMqzsoCMZGWxt9jBRK9hoBZj2A37i8joKhsyth2EuVKDVJCTF5/H4iEDw==
|
||||
version "14.2.21"
|
||||
resolved "https://registry.yarnpkg.com/next/-/next-14.2.21.tgz#f6da9e2abba1a0e4ca7a5273825daf06632554ba"
|
||||
integrity sha512-rZmLwucLHr3/zfDMYbJXbw0ZeoBpirxkXuvsJbk7UPorvPYZhP7vq7aHbKnU7dQNCYIimRrbB2pp3xmf+wsYUg==
|
||||
dependencies:
|
||||
"@next/env" "14.2.22"
|
||||
"@next/env" "14.2.21"
|
||||
"@swc/helpers" "0.5.5"
|
||||
busboy "1.6.0"
|
||||
caniuse-lite "^1.0.30001579"
|
||||
@@ -10052,15 +10050,15 @@ next@^14.2.20:
|
||||
postcss "8.4.31"
|
||||
styled-jsx "5.1.1"
|
||||
optionalDependencies:
|
||||
"@next/swc-darwin-arm64" "14.2.22"
|
||||
"@next/swc-darwin-x64" "14.2.22"
|
||||
"@next/swc-linux-arm64-gnu" "14.2.22"
|
||||
"@next/swc-linux-arm64-musl" "14.2.22"
|
||||
"@next/swc-linux-x64-gnu" "14.2.22"
|
||||
"@next/swc-linux-x64-musl" "14.2.22"
|
||||
"@next/swc-win32-arm64-msvc" "14.2.22"
|
||||
"@next/swc-win32-ia32-msvc" "14.2.22"
|
||||
"@next/swc-win32-x64-msvc" "14.2.22"
|
||||
"@next/swc-darwin-arm64" "14.2.21"
|
||||
"@next/swc-darwin-x64" "14.2.21"
|
||||
"@next/swc-linux-arm64-gnu" "14.2.21"
|
||||
"@next/swc-linux-arm64-musl" "14.2.21"
|
||||
"@next/swc-linux-x64-gnu" "14.2.21"
|
||||
"@next/swc-linux-x64-musl" "14.2.21"
|
||||
"@next/swc-win32-arm64-msvc" "14.2.21"
|
||||
"@next/swc-win32-ia32-msvc" "14.2.21"
|
||||
"@next/swc-win32-x64-msvc" "14.2.21"
|
||||
|
||||
no-case@^3.0.4:
|
||||
version "3.0.4"
|
||||
@@ -10369,15 +10367,6 @@ overlap-area@^1.1.0:
|
||||
dependencies:
|
||||
"@daybrush/utils" "^1.7.1"
|
||||
|
||||
own-keys@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/own-keys/-/own-keys-1.0.1.tgz#e4006910a2bf913585289676eebd6f390cf51358"
|
||||
integrity sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==
|
||||
dependencies:
|
||||
get-intrinsic "^1.2.6"
|
||||
object-keys "^1.1.1"
|
||||
safe-push-apply "^1.0.0"
|
||||
|
||||
p-limit@^2.0.0, p-limit@^2.2.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
|
||||
@@ -10927,9 +10916,9 @@ postgres@^3.4.4:
|
||||
integrity sha512-cDWgoah1Gez9rN3H4165peY9qfpEo+SA61oQv65O3cRUE1pOEoJWwddwcqKE8XZYjbblOJlYDlLV4h67HrEVDg==
|
||||
|
||||
posthog-js@^1.131.3:
|
||||
version "1.203.2"
|
||||
resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.203.2.tgz#ccbdb50f906ab10124cd8a9d31bd5ab2df542184"
|
||||
integrity sha512-3aLpEhM4i9sQQtobRmDttJ3rTW1+gwQ9HL7QiOeDueE2T7CguYibYS7weY1UhXMerx5lh1A7+szlOJTTibifLQ==
|
||||
version "1.203.1"
|
||||
resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.203.1.tgz#e1ce0ac65227d18b615f727ea4ec593694c6a33f"
|
||||
integrity sha512-r/WiSyz6VNbIKEV/30+aD5gdrYkFtmZwvqNa6h9frl8hG638v098FrXaq3EYzMcCdkQf3phaZTDIAFKegpiTjw==
|
||||
dependencies:
|
||||
core-js "^3.38.1"
|
||||
fflate "^0.4.8"
|
||||
@@ -10937,9 +10926,9 @@ posthog-js@^1.131.3:
|
||||
web-vitals "^4.2.0"
|
||||
|
||||
preact@^10.19.3:
|
||||
version "10.25.4"
|
||||
resolved "https://registry.yarnpkg.com/preact/-/preact-10.25.4.tgz#c1d00bee9d7b9dcd06a2311d9951973b506ae8ac"
|
||||
integrity sha512-jLdZDb+Q+odkHJ+MpW/9U5cODzqnB+fy2EiHSZES7ldV5LK7yjlVzTp7R8Xy6W6y75kfK8iWYtFVH7lvjwrCMA==
|
||||
version "10.25.3"
|
||||
resolved "https://registry.yarnpkg.com/preact/-/preact-10.25.3.tgz#22dfb072b088dda9a2bc6d4ca41bf46b588d325e"
|
||||
integrity sha512-dzQmIFtM970z+fP9ziQ3yG4e3ULIbwZzJ734vaMVUTaKQ2+Ru1Ou/gjshOYVHCcd1rpAelC6ngjvjDXph98unQ==
|
||||
|
||||
prebuild-install@^7.1.1:
|
||||
version "7.1.2"
|
||||
@@ -12020,14 +12009,6 @@ safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0:
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||
|
||||
safe-push-apply@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/safe-push-apply/-/safe-push-apply-1.0.0.tgz#01850e981c1602d398c85081f360e4e6d03d27f5"
|
||||
integrity sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==
|
||||
dependencies:
|
||||
es-errors "^1.3.0"
|
||||
isarray "^2.0.5"
|
||||
|
||||
safe-regex-test@^1.0.3, safe-regex-test@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz#7f87dfb67a3150782eaaf18583ff5d1711ac10c1"
|
||||
@@ -12979,17 +12960,17 @@ tiptap-markdown@^0.8.9:
|
||||
markdown-it-task-lists "^2.1.1"
|
||||
prosemirror-markdown "^1.11.1"
|
||||
|
||||
tldts-core@^6.1.70:
|
||||
version "6.1.70"
|
||||
resolved "https://registry.yarnpkg.com/tldts-core/-/tldts-core-6.1.70.tgz#a954e93237ece2e1705b438600793c86a25f8c00"
|
||||
integrity sha512-RNnIXDB1FD4T9cpQRErEqw6ZpjLlGdMOitdV+0xtbsnwr4YFka1zpc7D4KD+aAn8oSG5JyFrdasZTE04qDE9Yg==
|
||||
tldts-core@^6.1.69:
|
||||
version "6.1.69"
|
||||
resolved "https://registry.yarnpkg.com/tldts-core/-/tldts-core-6.1.69.tgz#079ffcac8a4407bc74567e292aecf30b943674e1"
|
||||
integrity sha512-nygxy9n2PBUFQUtAXAc122gGo+04/j5qr5TGQFZTHafTKYvmARVXt2cA5rgero2/dnXUfkdPtiJoKmrd3T+wdA==
|
||||
|
||||
tldts@^6.1.32:
|
||||
version "6.1.70"
|
||||
resolved "https://registry.yarnpkg.com/tldts/-/tldts-6.1.70.tgz#b571e5645ab9dc6f289453115d52602b8a384cfe"
|
||||
integrity sha512-/W1YVgYVJd9ZDjey5NXadNh0mJXkiUMUue9Zebd0vpdo1sU+H4zFFTaJ1RKD4N6KFoHfcXy6l+Vu7bh+bdWCzA==
|
||||
version "6.1.69"
|
||||
resolved "https://registry.yarnpkg.com/tldts/-/tldts-6.1.69.tgz#0fe1fcb1ad09510459693e72f96062cee2411f1f"
|
||||
integrity sha512-Oh/CqRQ1NXNY7cy9NkTPUauOWiTro0jEYZTioGbOmcQh6EC45oribyIMJp0OJO3677r13tO6SKdWoGZUx2BDFw==
|
||||
dependencies:
|
||||
tldts-core "^6.1.70"
|
||||
tldts-core "^6.1.69"
|
||||
|
||||
tmp@^0.0.33:
|
||||
version "0.0.33"
|
||||
|
||||
Reference in New Issue
Block a user