mirror of
https://github.com/System-End/nephthys.git
synced 2026-04-19 19:45:12 +00:00
editing and slugs and descs, i think i did slugs right?
This commit is contained in:
parent
575fa89192
commit
2e77f9f225
12 changed files with 414 additions and 38 deletions
|
|
@ -1,4 +1,5 @@
|
|||
import logging
|
||||
import re
|
||||
|
||||
from slack_bolt.async_app import AsyncAck
|
||||
from slack_sdk.web.async_client import AsyncWebClient
|
||||
|
|
@ -31,17 +32,31 @@ async def create_category_tag_view_callback(
|
|||
ack: AsyncAck, body: dict, client: AsyncWebClient
|
||||
):
|
||||
user_id = body["user"]["id"]
|
||||
values = body["view"]["state"]["values"]
|
||||
|
||||
raw_name = body["view"]["state"]["values"]["category_tag_name"][
|
||||
"category_tag_name"
|
||||
]["value"]
|
||||
raw_name = values["category_tag_name"]["category_tag_name"]["value"]
|
||||
name = raw_name.strip() if raw_name else ""
|
||||
|
||||
raw_slug = values["category_tag_slug"]["category_tag_slug"]["value"]
|
||||
slug = raw_slug.strip() if raw_slug else None
|
||||
|
||||
raw_description = values["category_tag_description"]["category_tag_description"][
|
||||
"value"
|
||||
]
|
||||
description = raw_description.strip() if raw_description else None
|
||||
|
||||
errors = {}
|
||||
|
||||
if not name:
|
||||
await ack(
|
||||
response_action="errors",
|
||||
errors={"category_tag_name": "Category name cannot be empty."},
|
||||
errors["category_tag_name"] = "Category name cannot be empty."
|
||||
|
||||
if slug and not re.match(r"^[a-z0-9_]+$", slug):
|
||||
errors["category_tag_slug"] = (
|
||||
"Slug must be snake_case (lowercase letters, numbers, and underscores only)."
|
||||
)
|
||||
|
||||
if errors:
|
||||
await ack(response_action="errors", errors=errors)
|
||||
return
|
||||
|
||||
user = await env.db.user.find_unique(where={"slackId": user_id})
|
||||
|
|
@ -53,17 +68,20 @@ async def create_category_tag_view_callback(
|
|||
return
|
||||
|
||||
try:
|
||||
await env.db.categorytag.create(
|
||||
data={"name": name, "createdBy": {"connect": {"id": user.id}}}
|
||||
)
|
||||
except UniqueViolationError:
|
||||
logging.warning(f"Duplicate category tag name: {name}")
|
||||
await ack(
|
||||
response_action="errors",
|
||||
errors={
|
||||
"category_tag_name": f"A category tag named '{name}' already exists."
|
||||
},
|
||||
data: dict = {"name": name, "createdBy": {"connect": {"id": user.id}}}
|
||||
if slug:
|
||||
data["slug"] = slug
|
||||
if description:
|
||||
data["description"] = description
|
||||
|
||||
await env.db.categorytag.create(data=data)
|
||||
except UniqueViolationError as e:
|
||||
logging.warning(f"Duplicate category tag: {e}")
|
||||
error_field = (
|
||||
"category_tag_slug" if slug and "slug" in str(e) else "category_tag_name"
|
||||
)
|
||||
error_msg = f"A category tag with this {'slug' if error_field == 'category_tag_slug' else 'name'} already exists."
|
||||
await ack(response_action="errors", errors={error_field: error_msg})
|
||||
return
|
||||
|
||||
await ack()
|
||||
|
|
|
|||
|
|
@ -21,9 +21,17 @@ async def create_team_tag_view_callback(
|
|||
await send_heartbeat(f"Attempted to create tag by non-admin user <@{user_id}>")
|
||||
return
|
||||
|
||||
name = body["view"]["state"]["values"]["tag_name"]["tag_name"]["value"]
|
||||
await env.db.tag.create(data={"name": name})
|
||||
values = body["view"]["state"]["values"]
|
||||
name = values["tag_name"]["tag_name"]["value"]
|
||||
|
||||
raw_description = values["tag_description"]["tag_description"]["value"]
|
||||
description = raw_description.strip() if raw_description else None
|
||||
|
||||
data: dict = {"name": name}
|
||||
if description:
|
||||
data["description"] = description
|
||||
|
||||
await env.db.tag.create(data=data)
|
||||
await open_app_home("team-tags", client, user_id)
|
||||
|
||||
|
||||
|
|
|
|||
92
nephthys/actions/edit_category_tag.py
Normal file
92
nephthys/actions/edit_category_tag.py
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
import logging
|
||||
import re
|
||||
|
||||
from slack_bolt.async_app import AsyncAck
|
||||
from slack_sdk.web.async_client import AsyncWebClient
|
||||
|
||||
from nephthys.utils.env import env
|
||||
from nephthys.utils.logging import send_heartbeat
|
||||
from nephthys.views.modals.edit_category_tag import get_edit_category_tag_modal
|
||||
from prisma.errors import UniqueViolationError
|
||||
|
||||
|
||||
async def edit_category_tag_btn_callback(
|
||||
ack: AsyncAck, body: dict, client: AsyncWebClient
|
||||
):
|
||||
await ack()
|
||||
user_id = body["user"]["id"]
|
||||
trigger_id = body["trigger_id"]
|
||||
tag_id = int(body["actions"][0]["value"])
|
||||
|
||||
user = await env.db.user.find_unique(where={"slackId": user_id})
|
||||
if not user or not user.admin:
|
||||
await send_heartbeat(
|
||||
f"Attempted to open edit category tag modal by non-admin user <@{user_id}>"
|
||||
)
|
||||
return
|
||||
|
||||
tag = await env.db.categorytag.find_unique(where={"id": tag_id})
|
||||
if not tag:
|
||||
logging.error(f"Category tag not found: id={tag_id}")
|
||||
return
|
||||
|
||||
view = get_edit_category_tag_modal(tag.id, tag.name, tag.slug, tag.description)
|
||||
await client.views_open(trigger_id=trigger_id, view=view, user_id=user_id)
|
||||
|
||||
|
||||
async def edit_category_tag_view_callback(
|
||||
ack: AsyncAck, body: dict, client: AsyncWebClient
|
||||
):
|
||||
user_id = body["user"]["id"]
|
||||
callback_id = body["view"]["callback_id"]
|
||||
tag_id = int(callback_id.replace("edit_category_tag_", ""))
|
||||
values = body["view"]["state"]["values"]
|
||||
|
||||
raw_name = values["category_tag_name"]["category_tag_name"]["value"]
|
||||
name = raw_name.strip() if raw_name else ""
|
||||
|
||||
raw_slug = values["category_tag_slug"]["category_tag_slug"]["value"]
|
||||
slug = raw_slug.strip() if raw_slug else None
|
||||
|
||||
raw_description = values["category_tag_description"]["category_tag_description"]["value"]
|
||||
description = raw_description.strip() if raw_description else None
|
||||
|
||||
errors = {}
|
||||
|
||||
if not name:
|
||||
errors["category_tag_name"] = "Category name cannot be empty."
|
||||
|
||||
if slug and not re.match(r"^[a-z0-9_]+$", slug):
|
||||
errors["category_tag_slug"] = (
|
||||
"Slug must be snake_case (lowercase letters, numbers, and underscores only)."
|
||||
)
|
||||
|
||||
if errors:
|
||||
await ack(response_action="errors", errors=errors)
|
||||
return
|
||||
|
||||
user = await env.db.user.find_unique(where={"slackId": user_id})
|
||||
if not user or not user.admin:
|
||||
await ack()
|
||||
await send_heartbeat(
|
||||
f"Attempted to edit category tag by non-admin user <@{user_id}>"
|
||||
)
|
||||
return
|
||||
|
||||
try:
|
||||
await env.db.categorytag.update(
|
||||
where={"id": tag_id},
|
||||
data={"name": name, "slug": slug, "description": description},
|
||||
)
|
||||
except UniqueViolationError as e:
|
||||
logging.warning(f"Duplicate category tag: {e}")
|
||||
error_field = "category_tag_slug" if slug and "slug" in str(e) else "category_tag_name"
|
||||
error_msg = f"A category tag with this {'slug' if error_field == 'category_tag_slug' else 'name'} already exists."
|
||||
await ack(response_action="errors", errors={error_field: error_msg})
|
||||
return
|
||||
|
||||
await ack()
|
||||
|
||||
from nephthys.events.app_home_opened import open_app_home
|
||||
|
||||
await open_app_home("category-tags", client, user_id)
|
||||
65
nephthys/actions/edit_team_tag.py
Normal file
65
nephthys/actions/edit_team_tag.py
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import logging
|
||||
|
||||
from slack_bolt.async_app import AsyncAck
|
||||
from slack_sdk.web.async_client import AsyncWebClient
|
||||
|
||||
from nephthys.utils.env import env
|
||||
from nephthys.utils.logging import send_heartbeat
|
||||
from nephthys.views.modals.edit_team_tag import get_edit_team_tag_modal
|
||||
|
||||
|
||||
async def edit_team_tag_btn_callback(
|
||||
ack: AsyncAck, body: dict, client: AsyncWebClient
|
||||
):
|
||||
await ack()
|
||||
user_id = body["user"]["id"]
|
||||
trigger_id = body["trigger_id"]
|
||||
tag_id = int(body["actions"][0]["value"])
|
||||
|
||||
user = await env.db.user.find_unique(where={"slackId": user_id})
|
||||
if not user or not user.admin:
|
||||
await send_heartbeat(
|
||||
f"Attempted to open edit team tag modal by non-admin user <@{user_id}>"
|
||||
)
|
||||
return
|
||||
|
||||
tag = await env.db.tag.find_unique(where={"id": tag_id})
|
||||
if not tag:
|
||||
logging.error(f"Team tag not found: id={tag_id}")
|
||||
return
|
||||
|
||||
view = get_edit_team_tag_modal(tag.id, tag.name, tag.description)
|
||||
await client.views_open(trigger_id=trigger_id, view=view, user_id=user_id)
|
||||
|
||||
|
||||
async def edit_team_tag_view_callback(
|
||||
ack: AsyncAck, body: dict, client: AsyncWebClient
|
||||
):
|
||||
await ack()
|
||||
user_id = body["user"]["id"]
|
||||
callback_id = body["view"]["callback_id"]
|
||||
tag_id = int(callback_id.replace("edit_team_tag_", ""))
|
||||
values = body["view"]["state"]["values"]
|
||||
|
||||
name = values["tag_name"]["tag_name"]["value"]
|
||||
|
||||
raw_description = values["tag_description"]["tag_description"]["value"]
|
||||
description = raw_description.strip() if raw_description else None
|
||||
|
||||
user = await env.db.user.find_unique(where={"slackId": user_id})
|
||||
if not user or not user.admin:
|
||||
await send_heartbeat(
|
||||
f"Attempted to edit team tag by non-admin user <@{user_id}>"
|
||||
)
|
||||
return
|
||||
|
||||
await env.db.tag.update(
|
||||
where={"id": tag_id},
|
||||
data={"name": name, "description": description},
|
||||
)
|
||||
|
||||
logging.info(f"Updated team tag id={tag_id} name={name} by <@{user_id}>")
|
||||
|
||||
from nephthys.events.app_home_opened import open_app_home
|
||||
|
||||
await open_app_home("team-tags", client, user_id)
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import logging
|
||||
import re
|
||||
from typing import Any
|
||||
from typing import Dict
|
||||
|
||||
|
|
@ -12,6 +13,10 @@ from nephthys.actions.create_category_tag import create_category_tag_btn_callbac
|
|||
from nephthys.actions.create_category_tag import create_category_tag_view_callback
|
||||
from nephthys.actions.create_team_tag import create_team_tag_btn_callback
|
||||
from nephthys.actions.create_team_tag import create_team_tag_view_callback
|
||||
from nephthys.actions.edit_category_tag import edit_category_tag_btn_callback
|
||||
from nephthys.actions.edit_category_tag import edit_category_tag_view_callback
|
||||
from nephthys.actions.edit_team_tag import edit_team_tag_btn_callback
|
||||
from nephthys.actions.edit_team_tag import edit_team_tag_view_callback
|
||||
from nephthys.actions.resolve import resolve
|
||||
from nephthys.actions.tag_subscribe import tag_subscribe_callback
|
||||
from nephthys.commands.dm_magic_link import dm_magic_link_cmd_callback
|
||||
|
|
@ -108,6 +113,18 @@ async def create_team_tag_view(
|
|||
await create_team_tag_view_callback(ack, body, client)
|
||||
|
||||
|
||||
@app.action(re.compile(r"^edit-team-tag-\d+$"))
|
||||
async def edit_team_tag(ack: AsyncAck, body: Dict[str, Any], client: AsyncWebClient):
|
||||
await edit_team_tag_btn_callback(ack, body, client)
|
||||
|
||||
|
||||
@app.view(re.compile(r"^edit_team_tag_\d+$"))
|
||||
async def edit_team_tag_view(
|
||||
ack: AsyncAck, body: Dict[str, Any], client: AsyncWebClient
|
||||
):
|
||||
await edit_team_tag_view_callback(ack, body, client)
|
||||
|
||||
|
||||
@app.action("create-category-tag")
|
||||
async def create_category_tag(
|
||||
ack: AsyncAck, body: Dict[str, Any], client: AsyncWebClient
|
||||
|
|
@ -122,6 +139,20 @@ async def create_category_tag_view(
|
|||
await create_category_tag_view_callback(ack, body, client)
|
||||
|
||||
|
||||
@app.action(re.compile(r"^edit-category-tag-\d+$"))
|
||||
async def edit_category_tag(
|
||||
ack: AsyncAck, body: Dict[str, Any], client: AsyncWebClient
|
||||
):
|
||||
await edit_category_tag_btn_callback(ack, body, client)
|
||||
|
||||
|
||||
@app.view(re.compile(r"^edit_category_tag_\d+$"))
|
||||
async def edit_category_tag_view(
|
||||
ack: AsyncAck, body: Dict[str, Any], client: AsyncWebClient
|
||||
):
|
||||
await edit_category_tag_view_callback(ack, body, client)
|
||||
|
||||
|
||||
@app.action("tag-subscribe")
|
||||
async def tag_subscribe(ack: AsyncAck, body: Dict[str, Any], client: AsyncWebClient):
|
||||
await tag_subscribe_callback(ack, body, client)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,22 @@ async def get_category_tags_view(user: User | None) -> dict:
|
|||
tag_blocks.append(Section(":rac_nooo: no category tags yet — add one below!"))
|
||||
else:
|
||||
for tag in category_tags:
|
||||
tag_blocks.append(Section(f"*{tag.name}*"))
|
||||
text = f"*{tag.name}*"
|
||||
if tag.slug:
|
||||
text += f"\n`{tag.slug}`"
|
||||
if tag.description:
|
||||
text += f"\n_{tag.description}_"
|
||||
|
||||
tag_blocks.append(
|
||||
Section(
|
||||
text=text,
|
||||
accessory=Button(
|
||||
text=":pencil2: Edit",
|
||||
action_id=f"edit-category-tag-{tag.id}",
|
||||
value=str(tag.id),
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
return Home(
|
||||
[
|
||||
|
|
|
|||
|
|
@ -37,12 +37,18 @@ async def get_team_tags_view(user: User | None) -> dict:
|
|||
else:
|
||||
subs = []
|
||||
stringified_subs = [f"<@{user}>" for user in subs]
|
||||
|
||||
tag_text = f"*{tag.name}*"
|
||||
if tag.description:
|
||||
tag_text += f"\n_{tag.description}_"
|
||||
tag_text += f"\n{''.join(stringified_subs) if stringified_subs else ':rac_nooo: no subscriptions'}"
|
||||
|
||||
blocks.append(
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": f"*{tag.name}* - {''.join(stringified_subs) if stringified_subs else ':rac_nooo: no subscriptions'}",
|
||||
"text": tag_text,
|
||||
},
|
||||
"accessory": (
|
||||
{
|
||||
|
|
@ -62,6 +68,25 @@ async def get_team_tags_view(user: User | None) -> dict:
|
|||
}
|
||||
)
|
||||
|
||||
if is_admin:
|
||||
blocks.append(
|
||||
{
|
||||
"type": "actions",
|
||||
"elements": [
|
||||
{
|
||||
"type": "button",
|
||||
"text": {
|
||||
"type": "plain_text",
|
||||
"text": ":pencil2: Edit tag",
|
||||
"emoji": True,
|
||||
},
|
||||
"action_id": f"edit-team-tag-{tag.id}",
|
||||
"value": str(tag.id),
|
||||
}
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
view = {
|
||||
"type": "home",
|
||||
"blocks": [
|
||||
|
|
|
|||
|
|
@ -14,7 +14,24 @@ def get_create_category_tag_modal():
|
|||
block_id="category_tag_name",
|
||||
element=PlainTextInput(action_id="category_tag_name"),
|
||||
),
|
||||
# future: description
|
||||
# future: slug
|
||||
Input(
|
||||
label="Slug (snake_case ID, optional)",
|
||||
block_id="category_tag_slug",
|
||||
optional=True,
|
||||
element=PlainTextInput(
|
||||
action_id="category_tag_slug",
|
||||
placeholder="e.g. payouts_issue or fulfillment_query",
|
||||
),
|
||||
),
|
||||
Input(
|
||||
label="Description (helps AI pick this category)",
|
||||
block_id="category_tag_description",
|
||||
optional=True,
|
||||
element=PlainTextInput(
|
||||
action_id="category_tag_description",
|
||||
multiline=True,
|
||||
placeholder="What kinds of questions should be tagged with this?",
|
||||
),
|
||||
),
|
||||
],
|
||||
).build()
|
||||
|
|
|
|||
|
|
@ -7,13 +7,18 @@ def get_create_team_tag_modal():
|
|||
"text": ":rac_info: create a tag!",
|
||||
"emoji": True,
|
||||
},
|
||||
"submit": {
|
||||
"type": "plain_text",
|
||||
"text": ":rac_question: add tag?",
|
||||
"emoji": True,
|
||||
},
|
||||
"blocks": [
|
||||
{
|
||||
"type": "input",
|
||||
"block_id": "tag_name",
|
||||
"label": {
|
||||
"type": "plain_text",
|
||||
"text": "giv name?",
|
||||
"text": "Name",
|
||||
"emoji": True,
|
||||
},
|
||||
"element": {
|
||||
|
|
@ -21,10 +26,24 @@ def get_create_team_tag_modal():
|
|||
"action_id": "tag_name",
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "input",
|
||||
"block_id": "tag_description",
|
||||
"optional": True,
|
||||
"label": {
|
||||
"type": "plain_text",
|
||||
"text": "Description (optional)",
|
||||
"emoji": True,
|
||||
},
|
||||
"element": {
|
||||
"type": "plain_text_input",
|
||||
"action_id": "tag_description",
|
||||
"multiline": True,
|
||||
"placeholder": {
|
||||
"type": "plain_text",
|
||||
"text": "What is this tag for?",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
"submit": {
|
||||
"type": "plain_text",
|
||||
"text": ":rac_question: add tag?",
|
||||
"emoji": True,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
47
nephthys/views/modals/edit_category_tag.py
Normal file
47
nephthys/views/modals/edit_category_tag.py
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
from blockkit import Input
|
||||
from blockkit import Modal
|
||||
from blockkit import PlainTextInput
|
||||
|
||||
|
||||
def get_edit_category_tag_modal(
|
||||
tag_id: int,
|
||||
name: str,
|
||||
slug: str | None,
|
||||
description: str | None,
|
||||
):
|
||||
return Modal(
|
||||
title=":pencil2: edit category",
|
||||
callback_id=f"edit_category_tag_{tag_id}",
|
||||
submit=":rac_thumbs: save",
|
||||
blocks=[
|
||||
Input(
|
||||
label="Category name",
|
||||
block_id="category_tag_name",
|
||||
element=PlainTextInput(
|
||||
action_id="category_tag_name",
|
||||
initial_value=name,
|
||||
),
|
||||
),
|
||||
Input(
|
||||
label="Slug (snake_case ID, optional)",
|
||||
block_id="category_tag_slug",
|
||||
optional=True,
|
||||
element=PlainTextInput(
|
||||
action_id="category_tag_slug",
|
||||
placeholder="e.g. payouts_issue or fulfillment_query",
|
||||
**({"initial_value": slug} if slug else {}),
|
||||
),
|
||||
),
|
||||
Input(
|
||||
label="Description (helps AI pick this category)",
|
||||
block_id="category_tag_description",
|
||||
optional=True,
|
||||
element=PlainTextInput(
|
||||
action_id="category_tag_description",
|
||||
multiline=True,
|
||||
placeholder="What kinds of questions should be tagged with this?",
|
||||
**({"initial_value": description} if description else {}),
|
||||
),
|
||||
),
|
||||
],
|
||||
).build()
|
||||
36
nephthys/views/modals/edit_team_tag.py
Normal file
36
nephthys/views/modals/edit_team_tag.py
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
def get_edit_team_tag_modal(tag_id: int, name: str, description: str | None):
|
||||
return {
|
||||
"type": "modal",
|
||||
"callback_id": f"edit_team_tag_{tag_id}",
|
||||
"title": {"type": "plain_text", "text": ":pencil2: edit tag", "emoji": True},
|
||||
"submit": {"type": "plain_text", "text": ":rac_thumbs: save", "emoji": True},
|
||||
"blocks": [
|
||||
{
|
||||
"type": "input",
|
||||
"block_id": "tag_name",
|
||||
"label": {"type": "plain_text", "text": "Name", "emoji": True},
|
||||
"element": {
|
||||
"type": "plain_text_input",
|
||||
"action_id": "tag_name",
|
||||
"initial_value": name,
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "input",
|
||||
"block_id": "tag_description",
|
||||
"optional": True,
|
||||
"label": {
|
||||
"type": "plain_text",
|
||||
"text": "Description (optional)",
|
||||
"emoji": True,
|
||||
},
|
||||
"element": {
|
||||
"type": "plain_text_input",
|
||||
"action_id": "tag_description",
|
||||
"multiline": True,
|
||||
"placeholder": {"type": "plain_text", "text": "What is this tag for?"},
|
||||
**({"initial_value": description} if description else {}),
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
|
@ -32,9 +32,9 @@ model User {
|
|||
assignedTickets Ticket[] @relation("AssignedTickets")
|
||||
reopenedTickets Ticket[] @relation("ReopenedTickets")
|
||||
|
||||
tagSubscriptions UserTagSubscription[]
|
||||
createdCategoryTags CategoryTag[] @relation("CreatedCategoryTags")
|
||||
helper Boolean @default(false)
|
||||
tagSubscriptions UserTagSubscription[]
|
||||
createdCategoryTags CategoryTag[] @relation("CreatedCategoryTags")
|
||||
helper Boolean @default(false)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
}
|
||||
|
|
@ -75,7 +75,7 @@ model Ticket {
|
|||
questionTag QuestionTag? @relation("QuestionTagTickets", fields: [questionTagId], references: [id])
|
||||
questionTagId Int?
|
||||
|
||||
categoryTag CategoryTag? @relation("CategoryTagTickets", fields: [categoryTagId], references: [id])
|
||||
categoryTag CategoryTag? @relation("CategoryTagTickets", fields: [categoryTagId], references: [id])
|
||||
categoryTagId Int?
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
|
|
@ -90,8 +90,9 @@ model QuestionTag {
|
|||
|
||||
// These tags are team tags
|
||||
model Tag {
|
||||
id Int @id @unique @default(autoincrement())
|
||||
name String @unique
|
||||
id Int @id @unique @default(autoincrement())
|
||||
name String @unique
|
||||
description String?
|
||||
|
||||
ticketsOnTags TagsOnTickets[]
|
||||
|
||||
|
|
@ -134,11 +135,13 @@ model BotMessage {
|
|||
}
|
||||
|
||||
model CategoryTag {
|
||||
id Int @id @unique @default(autoincrement())
|
||||
name String @unique
|
||||
tickets Ticket[] @relation("CategoryTagTickets")
|
||||
id Int @id @unique @default(autoincrement())
|
||||
name String @unique
|
||||
slug String? @unique
|
||||
description String?
|
||||
tickets Ticket[] @relation("CategoryTagTickets")
|
||||
|
||||
createdBy User? @relation("CreatedCategoryTags", fields: [createdById], references: [id])
|
||||
createdBy User? @relation("CreatedCategoryTags", fields: [createdById], references: [id])
|
||||
createdById Int?
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue