Compare commits
1 Commits
master
...
VORKOUT-16
Author | SHA1 | Date | |
---|---|---|---|
e10430310f |
@ -1,174 +0,0 @@
|
||||
from typing import Optional
|
||||
import math
|
||||
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from sqlalchemy import insert, select, func
|
||||
from sqlalchemy.ext.asyncio import AsyncConnection
|
||||
from enum import Enum
|
||||
|
||||
from api.db.tables.events import list_events_table
|
||||
|
||||
|
||||
from api.schemas.events.list_events import ListEvent
|
||||
|
||||
|
||||
from api.schemas.endpoints.list_events import all_list_event_adapter,AllListEventResponse
|
||||
|
||||
|
||||
async def get_listevents_page_by_creator_id(connection: AsyncConnection, creator_id: int, page: int, limit: int) -> Optional[AllListEventResponse]:
|
||||
"""
|
||||
Получает список событий заданного создателя по значениям page и limit и creator_id.
|
||||
"""
|
||||
|
||||
first_event = page * limit - limit
|
||||
query = (
|
||||
select(
|
||||
list_events_table.c.id,
|
||||
list_events_table.c.name,
|
||||
list_events_table.c.title,
|
||||
list_events_table.c.creator_id,
|
||||
list_events_table.c.created_at,
|
||||
list_events_table.c.schema_,
|
||||
list_events_table.c.state,
|
||||
list_events_table.c.status,
|
||||
)
|
||||
.where(list_events_table.c.creator_id == creator_id) # Фильтрация по creator_id
|
||||
.order_by(list_events_table.c.id)
|
||||
.offset(first_event)
|
||||
.limit(limit)
|
||||
)
|
||||
|
||||
count_query = (
|
||||
select(func.count())
|
||||
.select_from(list_events_table)
|
||||
.where(list_events_table.c.creator_id == creator_id) # Фильтрация по creator_id
|
||||
)
|
||||
|
||||
result = await connection.execute(query)
|
||||
count_result = await connection.execute(count_query)
|
||||
|
||||
events_data = result.mappings().all()
|
||||
total_count = count_result.scalar()
|
||||
total_pages = math.ceil(total_count / limit)
|
||||
|
||||
# Здесь предполагается, что all_list_event_adapter.validate_python корректно обрабатывает данные
|
||||
validated_list_event = all_list_event_adapter.validate_python(events_data)
|
||||
|
||||
return AllListEventResponse(list_event=validated_list_event, amount_count=total_count, amount_pages=total_pages, current_page=page,
|
||||
limit = limit)
|
||||
|
||||
|
||||
async def get_listevents_page(connection: AsyncConnection, page, limit) -> Optional[AllListEventResponse]:
|
||||
"""
|
||||
Получает список событий заданного создателя по значениям page и limit.
|
||||
"""
|
||||
|
||||
first_event = page * limit - (limit)
|
||||
|
||||
query = (
|
||||
select(
|
||||
list_events_table.c.id,
|
||||
list_events_table.c.name,
|
||||
list_events_table.c.title,
|
||||
list_events_table.c.creator_id,
|
||||
list_events_table.c.created_at,
|
||||
list_events_table.c.schema,
|
||||
list_events_table.c.state,
|
||||
list_events_table.c.status,
|
||||
)
|
||||
.order_by(list_events_table.c.id)
|
||||
.offset(first_event)
|
||||
.limit(limit)
|
||||
)
|
||||
|
||||
count_query = select(func.count()).select_from(list_events_table)
|
||||
|
||||
result = await connection.execute(query)
|
||||
count_result = await connection.execute(count_query)
|
||||
|
||||
events_data = result.mappings().all()
|
||||
total_count = count_result.scalar()
|
||||
total_pages = math.ceil(total_count / limit)
|
||||
|
||||
# Здесь предполагается, что all_list_event_adapter.validate_python корректно обрабатывает данные
|
||||
validated_list_event = all_list_event_adapter.validate_python(events_data)
|
||||
|
||||
return AllListEventResponse(list_event=validated_list_event, amount_count=total_count, amount_pages=total_pages,current_page=page,
|
||||
limit = limit)
|
||||
|
||||
async def get_listevents_by_name(connection: AsyncConnection, name: str) -> Optional[ListEvent]:
|
||||
"""
|
||||
Получает list events по name.
|
||||
"""
|
||||
query = select(list_events_table).where(list_events_table.c.name == name)
|
||||
|
||||
listevents_db_cursor = await connection.execute(query)
|
||||
listevents_db = listevents_db_cursor.one_or_none()
|
||||
|
||||
if not listevents_db:
|
||||
return None
|
||||
|
||||
listevents_data = {
|
||||
column.name: (
|
||||
getattr(listevents_db, column.name).name
|
||||
if isinstance(getattr(listevents_db, column.name), Enum)
|
||||
else getattr(listevents_db, column.name)
|
||||
)
|
||||
for column in list_events_table.columns
|
||||
}
|
||||
|
||||
return ListEvent.model_validate(listevents_data)
|
||||
|
||||
async def get_listevents_by_id(connection: AsyncConnection, id: int) -> Optional[ListEvent]:
|
||||
"""
|
||||
Получает listevent по id.
|
||||
"""
|
||||
query = select(list_events_table).where(list_events_table.c.id == id)
|
||||
|
||||
listevents_db_cursor = await connection.execute(query)
|
||||
listevents_db = listevents_db_cursor.one_or_none()
|
||||
|
||||
if not listevents_db:
|
||||
return None
|
||||
|
||||
listevents_data = {
|
||||
column.name: (
|
||||
getattr(listevents_db, column.name).name
|
||||
if isinstance(getattr(listevents_db, column.name), Enum)
|
||||
else getattr(listevents_db, column.name)
|
||||
)
|
||||
for column in list_events_table.columns
|
||||
}
|
||||
|
||||
return ListEvent.model_validate(listevents_data)
|
||||
|
||||
async def update_listevents_by_id(connection: AsyncConnection, update_values, listevents):
|
||||
"""
|
||||
Вносит изменеия в нужное поле таблицы list_events_table.
|
||||
"""
|
||||
await connection.execute(list_events_table.update().where(list_events_table.c.id == listevents.id).values(**update_values))
|
||||
|
||||
await connection.commit()
|
||||
|
||||
|
||||
|
||||
async def create_listevents(connection: AsyncConnection, listevents: ListEvent, creator_id: int) -> Optional[ListEvent]:
|
||||
"""
|
||||
Создает нове поле в таблице list_events_table.
|
||||
"""
|
||||
query = insert(list_events_table).values(
|
||||
name=listevents.name,
|
||||
title=listevents.title, # добавлено поле title
|
||||
creator_id=creator_id,
|
||||
created_at=datetime.now(timezone.utc),
|
||||
schema=listevents.schema_, # добавлено поле schema
|
||||
state=listevents.state.value, # добавлено поле state
|
||||
status=listevents.status.value # добавлено поле status
|
||||
)
|
||||
|
||||
await connection.execute(query)
|
||||
|
||||
await connection.commit()
|
||||
|
||||
return listevents
|
@ -3,6 +3,8 @@ import enum
|
||||
from sqlalchemy import Table, Column, String, Enum as SQLAEnum, JSON, ForeignKey, DateTime, Index
|
||||
from sqlalchemy.sql import func
|
||||
|
||||
from enum import Enum
|
||||
|
||||
from api.db.sql_types import UnsignedInt
|
||||
from api.db import metadata
|
||||
|
||||
|
@ -2,9 +2,8 @@ from api.endpoints.auth import api_router as auth_router
|
||||
from api.endpoints.profile import api_router as profile_router
|
||||
from api.endpoints.account import api_router as account_router
|
||||
from api.endpoints.keyring import api_router as keyring_router
|
||||
from api.endpoints.listevents import api_router as listevents_router
|
||||
|
||||
list_of_routes = [auth_router, profile_router, account_router, keyring_router,listevents_router]
|
||||
list_of_routes = [auth_router, profile_router, account_router, keyring_router]
|
||||
|
||||
__all__ = [
|
||||
"list_of_routes",
|
||||
|
@ -1,174 +0,0 @@
|
||||
from fastapi import (
|
||||
APIRouter,
|
||||
Depends,
|
||||
HTTPException,
|
||||
status,
|
||||
)
|
||||
|
||||
|
||||
from sqlalchemy.ext.asyncio import AsyncConnection
|
||||
|
||||
from api.db.connection.session import get_connection_dep
|
||||
|
||||
from api.db.logic.account import (
|
||||
get_user_by_login
|
||||
)
|
||||
|
||||
from api.db.logic.listevents import (
|
||||
get_listevents_by_name,
|
||||
get_listevents_by_id,
|
||||
create_listevents,
|
||||
update_listevents_by_id,
|
||||
get_listevents_page,
|
||||
get_listevents_page_by_creator_id
|
||||
|
||||
)
|
||||
|
||||
|
||||
from api.schemas.events.list_events import ListEvent
|
||||
from api.db.tables.events import EventStatus
|
||||
|
||||
from api.schemas.base import bearer_schema
|
||||
|
||||
from api.schemas.endpoints.list_events import ListEventUpdate,AllListEventResponse
|
||||
|
||||
from api.services.auth import get_current_user
|
||||
|
||||
from api.services.user_role_validation import db_user_role_validation_for_listevents_by_listevent_id,db_user_role_validation_for_listevents
|
||||
from api.services.update_data_validation import update_listevents_data_changes
|
||||
|
||||
|
||||
api_router = APIRouter(
|
||||
prefix="/listevents",
|
||||
tags=["list events"],
|
||||
)
|
||||
|
||||
@api_router.get("",
|
||||
dependencies=[Depends(bearer_schema)],
|
||||
response_model=AllListEventResponse)
|
||||
async def get_all_list_events(
|
||||
page: int = 1,
|
||||
limit: int = 10,
|
||||
connection: AsyncConnection = Depends(get_connection_dep),
|
||||
current_user=Depends(get_current_user),
|
||||
):
|
||||
|
||||
authorize_user,page_flag = await db_user_role_validation_for_listevents(connection, current_user)
|
||||
|
||||
if page_flag:
|
||||
|
||||
list_eventslist = await get_listevents_page(connection, page, limit)
|
||||
print(list_eventslist)
|
||||
if list_eventslist is None:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found")
|
||||
|
||||
return list_eventslist
|
||||
else:
|
||||
list_events_list = await get_listevents_page_by_creator_id(connection,authorize_user.id, page, limit)
|
||||
|
||||
if list_events_list is None:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found")
|
||||
|
||||
return list_events_list
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@api_router.get("/{listevents_id}", dependencies=[Depends(bearer_schema)], response_model=ListEvent)
|
||||
async def get_list_events(
|
||||
listevents_id: int,
|
||||
connection: AsyncConnection = Depends(get_connection_dep),
|
||||
current_user=Depends(get_current_user)
|
||||
):
|
||||
listevents_validation = await get_listevents_by_id(connection, listevents_id)
|
||||
|
||||
if listevents_validation is None:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found")
|
||||
|
||||
authorize_user = await db_user_role_validation_for_listevents_by_listevent_id(connection, current_user,listevents_validation.creator_id)
|
||||
|
||||
|
||||
if listevents_id is None:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found")
|
||||
|
||||
return listevents_validation
|
||||
|
||||
|
||||
@api_router.post("", dependencies=[Depends(bearer_schema)], response_model=ListEvent)
|
||||
async def create_list_events(
|
||||
listevents: ListEventUpdate,
|
||||
connection: AsyncConnection = Depends(get_connection_dep),
|
||||
current_user=Depends(get_current_user)
|
||||
):
|
||||
|
||||
user_validation = await get_user_by_login(connection, current_user)
|
||||
listevents_validation = await get_listevents_by_name(connection, listevents.name)
|
||||
|
||||
if listevents_validation is None:
|
||||
await create_listevents(connection, listevents, user_validation.id)
|
||||
listevents_new = await get_listevents_by_name(connection, listevents.name)
|
||||
return listevents_new
|
||||
|
||||
else:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST, detail="An List events with this information already exists."
|
||||
)
|
||||
|
||||
@api_router.put("/{listevents_id}", dependencies=[Depends(bearer_schema)], response_model=ListEvent)
|
||||
async def update_listevents(
|
||||
listevents_id: int,
|
||||
listevents_update: ListEventUpdate,
|
||||
connection: AsyncConnection = Depends(get_connection_dep),
|
||||
current_user=Depends(get_current_user),
|
||||
):
|
||||
|
||||
listevents_validation = await get_listevents_by_id(connection, listevents_id)
|
||||
|
||||
if listevents_validation is None:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found")
|
||||
|
||||
authorize_user = await db_user_role_validation_for_listevents_by_listevent_id(connection, current_user,listevents_validation.creator_id)
|
||||
|
||||
update_values = update_listevents_data_changes(listevents_update, listevents_validation)
|
||||
|
||||
if update_values is None:
|
||||
return listevents_validation
|
||||
|
||||
listevents_update_data = ListEvent.model_validate({**listevents_validation.model_dump(), **update_values})
|
||||
|
||||
await update_listevents_by_id(connection, update_values, listevents_validation)
|
||||
|
||||
listevents = await get_listevents_by_id(connection, listevents_id)
|
||||
|
||||
return listevents
|
||||
|
||||
|
||||
@api_router.delete("/{listevents_id}", dependencies=[Depends(bearer_schema)], response_model=ListEvent)
|
||||
async def delete_list_events(
|
||||
listevents_id: int,
|
||||
connection: AsyncConnection = Depends(get_connection_dep),
|
||||
current_user=Depends(get_current_user),
|
||||
):
|
||||
|
||||
listevents_validation = await get_listevents_by_id(connection, listevents_id)
|
||||
|
||||
if listevents_validation is None:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found")
|
||||
|
||||
authorize_user = await db_user_role_validation_for_listevents_by_listevent_id(connection, current_user,listevents_validation.creator_id)
|
||||
|
||||
listevents_update = ListEventUpdate(status=EventStatus.DELETED.value)
|
||||
|
||||
|
||||
update_values = update_listevents_data_changes(listevents_update, listevents_validation)
|
||||
|
||||
if update_values is None:
|
||||
return listevents_validation
|
||||
|
||||
await update_listevents_by_id(connection, update_values, listevents_validation)
|
||||
|
||||
listevents = await get_listevents_by_id(connection, listevents_id)
|
||||
|
||||
return listevents
|
@ -8,6 +8,7 @@ from api.schemas.base import Base
|
||||
|
||||
|
||||
class UserUpdate(Base):
|
||||
id: Optional[int] = None
|
||||
name: Optional[str] = Field(None, max_length=100)
|
||||
login: Optional[str] = Field(None, max_length=100)
|
||||
email: Optional[EmailStr] = None
|
||||
@ -15,6 +16,8 @@ class UserUpdate(Base):
|
||||
bind_tenant_id: Optional[str] = Field(None, max_length=40)
|
||||
role: Optional[AccountRole] = None
|
||||
meta: Optional[dict] = None
|
||||
creator_id: Optional[int] = None
|
||||
created_at: Optional[datetime] = None
|
||||
status: Optional[AccountStatus] = None
|
||||
|
||||
|
||||
|
@ -10,5 +10,8 @@ from api.schemas.base import Base
|
||||
class AccountKeyringUpdate(Base):
|
||||
owner_id: Optional[int] = None
|
||||
key_type: Optional[KeyType] = None
|
||||
key_id: Optional[str] = Field(None, max_length=40)
|
||||
key_value: Optional[str] = Field(None, max_length=255)
|
||||
created_at: Optional[datetime] = None
|
||||
expiry: Optional[datetime] = None
|
||||
status: Optional[KeyStatus] = None
|
||||
|
@ -1,35 +0,0 @@
|
||||
from pydantic import Field, TypeAdapter
|
||||
from typing import Optional,Dict, Any, List
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
from api.schemas.base import Base
|
||||
from api.db.tables.events import EventState,EventStatus
|
||||
|
||||
|
||||
class ListEventUpdate(Base):
|
||||
name: Optional[str] = Field(None, max_length=40)
|
||||
title: Optional[str] = Field(None, max_length=64)
|
||||
schema_: Optional[Dict[str, Any]]= Field(None, alias="schema")
|
||||
state: Optional[EventState]= None
|
||||
status: Optional[EventStatus]= None
|
||||
|
||||
class AllListEvent(Base):
|
||||
id: int
|
||||
name: str
|
||||
title: str
|
||||
creator_id: int
|
||||
created_at: datetime
|
||||
schema_: Dict[str, Any] = Field(default={}, alias="schema")
|
||||
state: EventState
|
||||
status: EventStatus
|
||||
|
||||
|
||||
class AllListEventResponse(Base):
|
||||
list_event: List[AllListEvent]
|
||||
amount_count: int
|
||||
amount_pages: int
|
||||
current_page: int
|
||||
limit: int
|
||||
|
||||
all_list_event_adapter = TypeAdapter(List[AllListEvent])
|
@ -1,9 +1,20 @@
|
||||
from pydantic import Field
|
||||
from typing import Dict, Any
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
|
||||
from api.schemas.base import Base
|
||||
from api.db.tables.events import EventState,EventStatus
|
||||
|
||||
|
||||
class State(Enum):
|
||||
AUTO = "Auto"
|
||||
DESCRIPTED = "Descripted"
|
||||
|
||||
|
||||
class Status(Enum):
|
||||
ACTIVE = "Active"
|
||||
DISABLED = "Disabled"
|
||||
DELETED = "Deleted"
|
||||
|
||||
|
||||
class ListEvent(Base):
|
||||
@ -12,6 +23,6 @@ class ListEvent(Base):
|
||||
title: str = Field(..., max_length=64)
|
||||
creator_id: int
|
||||
created_at: datetime
|
||||
schema_: Dict[str, Any] = Field(..., alias="schema")
|
||||
state: EventState
|
||||
status: EventStatus
|
||||
schema: Dict[str, Any]
|
||||
state: State
|
||||
status: Status
|
||||
|
@ -4,8 +4,6 @@ from api.schemas.endpoints.account import UserUpdate
|
||||
from api.db.tables.account import KeyType, KeyStatus
|
||||
from api.schemas.endpoints.account_keyring import AccountKeyringUpdate
|
||||
from api.db.tables.account import AccountRole, AccountStatus
|
||||
from api.schemas.endpoints.list_events import ListEventUpdate
|
||||
from api.db.tables.events import EventState, EventStatus
|
||||
|
||||
|
||||
def update_user_data_changes(update_data: UserUpdate, user) -> Optional[dict]:
|
||||
@ -74,36 +72,3 @@ def update_key_data_changes(update_data: AccountKeyringUpdate, key) -> Optional[
|
||||
changes[field] = new_value
|
||||
|
||||
return changes if changes else None
|
||||
|
||||
def update_listevents_data_changes(update_data: ListEventUpdate, listevents) -> Optional[dict]:
|
||||
"""
|
||||
Сравнивает данные для обновления с текущими значениями listevents.
|
||||
Возвращает:
|
||||
- None, если нет изменений
|
||||
- Словарь {поле: новое_значение} для измененных полей
|
||||
"""
|
||||
update_values = {}
|
||||
changes = {}
|
||||
|
||||
for field, value in update_data.model_dump(exclude_unset=True).items():
|
||||
if value is None:
|
||||
continue
|
||||
|
||||
if isinstance(value, (EventState, EventStatus)):
|
||||
update_values[field] = value.value
|
||||
else:
|
||||
update_values[field] = value
|
||||
|
||||
for field, new_value in update_values.items():
|
||||
if not hasattr(listevents, field):
|
||||
continue
|
||||
|
||||
current_value = getattr(listevents, field)
|
||||
|
||||
if isinstance(current_value, Enum):
|
||||
current_value = current_value.value
|
||||
|
||||
if current_value != new_value:
|
||||
changes[field] = new_value
|
||||
|
||||
return changes if changes else None
|
||||
|
@ -11,17 +11,3 @@ async def db_user_role_validation(connection, current_user):
|
||||
if authorize_user.role not in {AccountRole.OWNER, AccountRole.ADMIN}:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="You do not have enough permissions")
|
||||
return authorize_user
|
||||
|
||||
async def db_user_role_validation_for_listevents_by_listevent_id(connection, current_user,current_listevents_creator_id):
|
||||
authorize_user = await get_user_by_login(connection, current_user)
|
||||
if authorize_user.role not in {AccountRole.OWNER, AccountRole.ADMIN}:
|
||||
if authorize_user.id != current_listevents_creator_id:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="You do not have enough permissions")
|
||||
return authorize_user
|
||||
|
||||
async def db_user_role_validation_for_listevents(connection, current_user):
|
||||
authorize_user = await get_user_by_login(connection, current_user)
|
||||
if authorize_user.role not in {AccountRole.OWNER, AccountRole.ADMIN}:
|
||||
return authorize_user,False
|
||||
else:
|
||||
return authorize_user,True
|
||||
|
234
client/package-lock.json
generated
234
client/package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "client",
|
||||
"version": "0.0.3",
|
||||
"version": "0.0.5",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "client",
|
||||
"version": "0.0.3",
|
||||
"version": "0.0.5",
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^5.6.1",
|
||||
"@testing-library/dom": "^10.4.0",
|
||||
@ -16,6 +16,7 @@
|
||||
"@types/jest": "^27.5.2",
|
||||
"@types/react": "^19.0.11",
|
||||
"@types/react-dom": "^19.0.4",
|
||||
"@xyflow/react": "^12.8.1",
|
||||
"antd": "^5.24.7",
|
||||
"axios": "^1.9.0",
|
||||
"axios-retry": "^4.5.0",
|
||||
@ -1567,6 +1568,55 @@
|
||||
"@babel/types": "^7.20.7"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/d3-color": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz",
|
||||
"integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/d3-drag": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz",
|
||||
"integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/d3-selection": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/d3-interpolate": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz",
|
||||
"integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/d3-color": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/d3-selection": {
|
||||
"version": "3.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz",
|
||||
"integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/d3-transition": {
|
||||
"version": "3.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz",
|
||||
"integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/d3-selection": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/d3-zoom": {
|
||||
"version": "3.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz",
|
||||
"integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/d3-interpolate": "*",
|
||||
"@types/d3-selection": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
||||
@ -1633,6 +1683,66 @@
|
||||
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@xyflow/react": {
|
||||
"version": "12.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@xyflow/react/-/react-12.8.1.tgz",
|
||||
"integrity": "sha512-t5Rame4Gc/540VcOZd28yFe9Xd8lyjKUX+VTiyb1x4ykNXZH5zyDmsu+lj9je2O/jGBVb0pj1Vjcxrxyn+Xk2g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@xyflow/system": "0.0.65",
|
||||
"classcat": "^5.0.3",
|
||||
"zustand": "^4.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=17",
|
||||
"react-dom": ">=17"
|
||||
}
|
||||
},
|
||||
"node_modules/@xyflow/react/node_modules/zustand": {
|
||||
"version": "4.5.7",
|
||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.7.tgz",
|
||||
"integrity": "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"use-sync-external-store": "^1.2.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.7.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": ">=16.8",
|
||||
"immer": ">=9.0.6",
|
||||
"react": ">=16.8"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"immer": {
|
||||
"optional": true
|
||||
},
|
||||
"react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@xyflow/system": {
|
||||
"version": "0.0.65",
|
||||
"resolved": "https://registry.npmjs.org/@xyflow/system/-/system-0.0.65.tgz",
|
||||
"integrity": "sha512-AliQPQeurQMoNlOdySnRoDQl9yDSA/1Lqi47Eo0m98lHcfrTdD9jK75H0tiGj+0qRC10SKNUXyMkT0KL0opg4g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/d3-drag": "^3.0.7",
|
||||
"@types/d3-interpolate": "^3.0.4",
|
||||
"@types/d3-selection": "^3.0.10",
|
||||
"@types/d3-transition": "^3.0.8",
|
||||
"@types/d3-zoom": "^3.0.8",
|
||||
"d3-drag": "^3.0.0",
|
||||
"d3-interpolate": "^3.0.1",
|
||||
"d3-selection": "^3.0.0",
|
||||
"d3-zoom": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
@ -2160,6 +2270,12 @@
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/classcat": {
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/classcat/-/classcat-5.0.5.tgz",
|
||||
"integrity": "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/classnames": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
|
||||
@ -2340,6 +2456,111 @@
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/d3-color": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
|
||||
"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-dispatch": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
|
||||
"integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-drag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
|
||||
"integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"d3-dispatch": "1 - 3",
|
||||
"d3-selection": "3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-ease": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
|
||||
"integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-interpolate": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
|
||||
"integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"d3-color": "1 - 3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-selection": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
|
||||
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-timer": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
|
||||
"integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-transition": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz",
|
||||
"integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"d3-color": "1 - 3",
|
||||
"d3-dispatch": "1 - 3",
|
||||
"d3-ease": "1 - 3",
|
||||
"d3-interpolate": "1 - 3",
|
||||
"d3-timer": "1 - 3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"d3-selection": "2 - 3"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-zoom": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz",
|
||||
"integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"d3-dispatch": "1 - 3",
|
||||
"d3-drag": "2 - 3",
|
||||
"d3-interpolate": "1 - 3",
|
||||
"d3-selection": "2 - 3",
|
||||
"d3-transition": "2 - 3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/dayjs": {
|
||||
"version": "1.11.13",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
|
||||
@ -5107,6 +5328,15 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/use-sync-external-store": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz",
|
||||
"integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/util": {
|
||||
"version": "0.12.5",
|
||||
"resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz",
|
||||
|
@ -11,6 +11,7 @@
|
||||
"@types/jest": "^27.5.2",
|
||||
"@types/react": "^19.0.11",
|
||||
"@types/react-dom": "^19.0.4",
|
||||
"@xyflow/react": "^12.8.1",
|
||||
"antd": "^5.24.7",
|
||||
"axios": "^1.9.0",
|
||||
"axios-retry": "^4.5.0",
|
||||
|
Loading…
Reference in New Issue
Block a user