diff --git a/.env.example b/.env.example index be50282..29709ad 100644 --- a/.env.example +++ b/.env.example @@ -10,6 +10,16 @@ BASE_PATH=/cc-dashboard APP_TITLE=CC Dashboard LOG_FORMAT=json +# Azure AD SSO (Oliver tenant — shared) +AZURE_TENANT_ID=e519c2e6-bc6d-4fdf-8d9c-923c2f002385 +AZURE_CLIENT_ID=9079054c-9620-4757-a256-23413042f1ef +ALLOWED_EMAIL_DOMAIN=oliver.agency +# Comma-separated emails that auto-receive admin role on first SSO login +ADMIN_EMAILS=vadymsamoilenko@oliver.agency +# Local dev only — set to true to skip SSO and auto-login as DEV_USER_EMAIL +DEV_AUTH_BYPASS=false +DEV_USER_EMAIL=vadymsamoilenko@oliver.agency + # Azure DevOps ADO_ORGANIZATION=your-org ADO_PROJECT=your-project diff --git a/alembic/versions/0007_sso_user_columns.py b/alembic/versions/0007_sso_user_columns.py new file mode 100644 index 0000000..d61f8c6 --- /dev/null +++ b/alembic/versions/0007_sso_user_columns.py @@ -0,0 +1,29 @@ +"""Add azure_oid to users and make password_hash nullable + +Revision ID: 0007 +Revises: 0006 +Create Date: 2026-05-07 +""" +import sqlalchemy as sa +from alembic import op + +revision = "0007" +down_revision = "0006" +branch_labels = None +depends_on = None + + +def upgrade(): + op.add_column("users", sa.Column("azure_oid", sa.String(36), nullable=True)) + op.create_unique_constraint("uq_users_azure_oid", "users", ["azure_oid"]) + op.create_index("ix_users_azure_oid", "users", ["azure_oid"]) + op.alter_column("users", "password_hash", existing_type=sa.String(255), nullable=True) + # Normalize existing emails to lowercase + op.execute("UPDATE users SET email = LOWER(email)") + + +def downgrade(): + op.drop_index("ix_users_azure_oid", table_name="users") + op.drop_constraint("uq_users_azure_oid", "users", type_="unique") + op.drop_column("users", "azure_oid") + op.alter_column("users", "password_hash", existing_type=sa.String(255), nullable=False) diff --git a/scripts/grant_admin.py b/scripts/grant_admin.py new file mode 100644 index 0000000..ea36687 --- /dev/null +++ b/scripts/grant_admin.py @@ -0,0 +1,32 @@ +"""Grant admin role to a user by email (SSO users). + +Usage: + docker compose exec app python scripts/grant_admin.py user@oliver.agency +""" +import asyncio +import sys + +from sqlalchemy import func, select + +from src.database import async_session_factory +from src.models import User + + +async def grant_admin(email: str) -> None: + email = email.strip().lower() + async with async_session_factory() as db: + result = await db.execute(select(User).where(func.lower(User.email) == email)) + user = result.scalar_one_or_none() + if user is None: + print(f"User {email!r} not found. They must log in via SSO first.") + sys.exit(1) + user.role = "admin" + await db.commit() + print(f"Granted admin to {user.email} (id={user.id})") + + +if __name__ == "__main__": + if len(sys.argv) != 2: + print("Usage: python scripts/grant_admin.py user@oliver.agency") + sys.exit(1) + asyncio.run(grant_admin(sys.argv[1])) diff --git a/src/auth.py b/src/auth.py index fc356f7..136e7fc 100644 --- a/src/auth.py +++ b/src/auth.py @@ -90,8 +90,19 @@ async def get_current_user( credentials: Annotated[HTTPAuthorizationCredentials | None, Security(bearer_scheme)], db: AsyncSession = Depends(get_db), ) -> User: + from src.config import settings + from sqlalchemy import select as sa_select, func + if not credentials: + if settings.DEV_AUTH_BYPASS: + result = await db.execute( + sa_select(User).where(func.lower(User.email) == settings.DEV_USER_EMAIL.lower()) + ) + user = result.scalar_one_or_none() + if user and user.is_active: + return user raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Not authenticated") + payload = decode_token(credentials.credentials) if payload.get("type") != "access": raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token type") diff --git a/src/config.py b/src/config.py index 407a26e..fc8b5fe 100644 --- a/src/config.py +++ b/src/config.py @@ -36,6 +36,14 @@ class Settings(BaseSettings): WEEKLY_REPORT_DAY: int = 6 # 0=Mon ... 6=Sun WEEKLY_REPORT_HOUR: int = 21 + # Azure AD SSO + AZURE_TENANT_ID: str = "" + AZURE_CLIENT_ID: str = "" + ALLOWED_EMAIL_DOMAIN: str = "oliver.agency" + ADMIN_EMAILS: str = "" # comma-separated lowercase + DEV_AUTH_BYPASS: bool = False + DEV_USER_EMAIL: str = "vadymsamoilenko@oliver.agency" + # Logging LOG_FORMAT: str = "console" # "json" or "console" diff --git a/src/models.py b/src/models.py index d725d44..6f9e9d3 100644 --- a/src/models.py +++ b/src/models.py @@ -33,7 +33,8 @@ class User(Base): id: Mapped[str] = mapped_column(UUID(as_uuid=False), primary_key=True, default=new_uuid) email: Mapped[str] = mapped_column(String(255), unique=True, nullable=False, index=True) username: Mapped[str] = mapped_column(String(100), unique=True, nullable=False) - password_hash: Mapped[str] = mapped_column(String(255), nullable=False) + password_hash: Mapped[str | None] = mapped_column(String(255), nullable=True) + azure_oid: Mapped[str | None] = mapped_column(String(36), nullable=True, unique=True, index=True) role: Mapped[str] = mapped_column(Enum("admin", "user", name="user_role"), default="user", nullable=False) is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) daily_overhead_hours: Mapped[float] = mapped_column(Float, default=0.0, nullable=False) diff --git a/src/routers/admin.py b/src/routers/admin.py index 0305ba5..e652bfe 100644 --- a/src/routers/admin.py +++ b/src/routers/admin.py @@ -22,9 +22,9 @@ async def create_user(body: UserCreate, admin: AdminUser, db: AsyncSession = Dep if exists.scalar_one_or_none(): raise HTTPException(status_code=400, detail="Email already registered") user = User( - email=body.email, + email=body.email.lower(), username=body.username, - password_hash=hash_password(body.password), + password_hash=hash_password(body.password) if body.password else None, role=body.role, ) db.add(user) diff --git a/src/routers/auth.py b/src/routers/auth.py index 73495cc..2b6acad 100644 --- a/src/routers/auth.py +++ b/src/routers/auth.py @@ -1,27 +1,73 @@ from fastapi import APIRouter, Depends, HTTPException, status -from sqlalchemy import select +from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession from src.auth import ( CurrentUser, create_access_token, create_refresh_token, - decode_token, hash_password, verify_password, + decode_token, hash_password, ) +from src.config import settings from src.database import get_db from src.models import User -from src.schemas import ( - ChangePasswordRequest, LoginRequest, RefreshRequest, - TokenResponse, UserOut, -) +from src.schemas import MicrosoftLoginRequest, RefreshRequest, TokenResponse, UserOut +from src.sso import validate_microsoft_id_token router = APIRouter(prefix="/api/auth", tags=["auth"]) -@router.post("/login", response_model=TokenResponse) -async def login(body: LoginRequest, db: AsyncSession = Depends(get_db)): - result = await db.execute(select(User).where(User.email == body.email)) - user = result.scalar_one_or_none() - if not user or not user.is_active or not verify_password(body.password, user.password_hash): - raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid credentials") +def _admin_set() -> set[str]: + return {e.strip().lower() for e in settings.ADMIN_EMAILS.split(",") if e.strip()} + + +@router.post("/microsoft", response_model=TokenResponse) +async def microsoft_sso(body: MicrosoftLoginRequest, db: AsyncSession = Depends(get_db)): + claims = validate_microsoft_id_token(body.id_token) + + raw_email = claims.get("preferred_username") or claims.get("email") or "" + email = raw_email.lower() + oid: str = claims.get("oid", "") + name: str = claims.get("name", "") + + if not email or not email.endswith(f"@{settings.ALLOWED_EMAIL_DOMAIN}"): + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Domain not allowed") + + # Find by azure_oid first (most stable), fall back to email match + user: User | None = None + if oid: + result = await db.execute(select(User).where(User.azure_oid == oid)) + user = result.scalar_one_or_none() + + if user is None: + result = await db.execute( + select(User).where(func.lower(User.email) == email) + ) + user = result.scalar_one_or_none() + + if user is None: + # First-time SSO login — auto-provision + username = email.split("@")[0] + user = User( + email=email, + username=username, + password_hash=None, + azure_oid=oid or None, + role="admin" if email in _admin_set() else "user", + ) + db.add(user) + else: + # Link existing account to Azure OID on first SSO login + if oid and user.azure_oid is None: + user.azure_oid = oid + # Promote to admin if listed + if email in _admin_set() and user.role != "admin": + user.role = "admin" + # Normalize email to lowercase (case-insensitive matching) + if user.email != email: + user.email = email + + await db.commit() + await db.refresh(user) + return TokenResponse( access_token=create_access_token(user.id, user.role), refresh_token=create_refresh_token(user.id), @@ -42,19 +88,6 @@ async def refresh(body: RefreshRequest, db: AsyncSession = Depends(get_db)): ) -@router.post("/change-password") -async def change_password( - body: ChangePasswordRequest, - user: CurrentUser, - db: AsyncSession = Depends(get_db), -): - if not verify_password(body.current_password, user.password_hash): - raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Wrong current password") - user.password_hash = hash_password(body.new_password) - await db.commit() - return {"detail": "Password changed"} - - @router.get("/me", response_model=UserOut) async def me(user: CurrentUser): return user diff --git a/src/schemas.py b/src/schemas.py index b1dc7f0..b358498 100644 --- a/src/schemas.py +++ b/src/schemas.py @@ -6,9 +6,8 @@ from pydantic import BaseModel, EmailStr, Field # ── Auth ────────────────────────────────────────────────────────────────────── -class LoginRequest(BaseModel): - email: EmailStr - password: str +class MicrosoftLoginRequest(BaseModel): + id_token: str class TokenResponse(BaseModel): @@ -21,11 +20,6 @@ class RefreshRequest(BaseModel): refresh_token: str -class ChangePasswordRequest(BaseModel): - current_password: str - new_password: str = Field(min_length=8) - - # ── Users ───────────────────────────────────────────────────────────────────── class UserOut(BaseModel): @@ -43,7 +37,7 @@ class UserOut(BaseModel): class UserCreate(BaseModel): email: EmailStr username: str = Field(min_length=2, max_length=100) - password: str = Field(min_length=8) + password: str | None = Field(default=None, min_length=8) role: str = Field(default="user", pattern="^(admin|user)$") diff --git a/src/sso.py b/src/sso.py new file mode 100644 index 0000000..f8ea618 --- /dev/null +++ b/src/sso.py @@ -0,0 +1,55 @@ +"""Azure AD SSO — validates Microsoft ID tokens via JWKS.""" +import time +from typing import Any + +import httpx +from fastapi import HTTPException, status +from jose import JWTError, jwt + +from src.config import settings + +_jwks_cache: dict[str, Any] = {} +_jwks_fetched_at: float = 0.0 +_JWKS_TTL = 3600 # seconds + + +def _get_jwks() -> dict: + global _jwks_cache, _jwks_fetched_at + if time.time() - _jwks_fetched_at < _JWKS_TTL and _jwks_cache: + return _jwks_cache + url = f"https://login.microsoftonline.com/{settings.AZURE_TENANT_ID}/discovery/v2.0/keys" + resp = httpx.get(url, timeout=10) + resp.raise_for_status() + _jwks_cache = resp.json() + _jwks_fetched_at = time.time() + return _jwks_cache + + +def validate_microsoft_id_token(id_token: str) -> dict: + """Validate Azure AD ID token and return claims. Raises 401 on any failure.""" + if not settings.AZURE_TENANT_ID or not settings.AZURE_CLIENT_ID: + raise HTTPException( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + detail="SSO not configured", + ) + try: + jwks = _get_jwks() + claims = jwt.decode( + id_token, + jwks, + algorithms=["RS256"], + audience=settings.AZURE_CLIENT_ID, + issuer=f"https://login.microsoftonline.com/{settings.AZURE_TENANT_ID}/v2.0", + options={"verify_at_hash": False}, + ) + return claims + except JWTError as exc: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=f"Invalid Microsoft token: {exc}", + ) + except httpx.HTTPError as exc: + raise HTTPException( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + detail=f"Failed to fetch Azure AD keys: {exc}", + ) diff --git a/src/static/assets/AdminView-9bHvBNlr.js b/src/static/assets/AdminView-9bHvBNlr.js deleted file mode 100644 index 5266d1c..0000000 --- a/src/static/assets/AdminView-9bHvBNlr.js +++ /dev/null @@ -1 +0,0 @@ -import{d as p,u as y,x as h,c as r,a as t,e as n,n as v,w as d,f as b,r as u,o as s,F as g,l as k,t as a,k as m,i as A}from"./index-yrXqsixb.js";import{a as w}from"./admin-BRKJZipt.js";import{_ as B,a as S}from"./CardContent.vue_vue_type_script_setup_true_lang-BZS0eQer.js";import{_ as x}from"./Badge.vue_vue_type_script_setup_true_lang-18ft6dLh.js";import{_ as V,a as $}from"./utils-D_0J15Md.js";const N={class:"p-6"},C={key:0,class:"flex items-center justify-center h-20"},D={class:"w-full"},E={class:"px-4 py-3"},F={class:"text-sm font-medium text-foreground"},R={class:"px-4 py-3 text-sm text-muted-foreground"},U={class:"px-4 py-3"},j={class:"px-4 py-3"},I={class:"px-4 py-3 text-xs text-muted-foreground"},G=p({__name:"AdminView",setup(J){const f=y(),_=b(),i=u([]),l=u(!1);return h(async()=>{if(!f.isAdmin){_.push("/");return}l.value=!0;try{const c=await w.users();i.value=c.data}finally{l.value=!1}}),(c,o)=>(s(),r("div",N,[o[1]||(o[1]=t("h2",{class:"text-lg font-semibold text-foreground mb-6"},"Admin — Users",-1)),l.value?(s(),r("div",C,[n(V,{class:"text-primary"})])):(s(),v(B,{key:1},{default:d(()=>[n(S,{class:"p-0"},{default:d(()=>[t("table",D,[o[0]||(o[0]=t("thead",null,[t("tr",{class:"border-b border-border"},[t("th",{class:"text-left text-xs font-medium text-muted-foreground px-4 py-3"},"User"),t("th",{class:"text-left text-xs font-medium text-muted-foreground px-4 py-3"},"Email"),t("th",{class:"text-left text-xs font-medium text-muted-foreground px-4 py-3"},"Role"),t("th",{class:"text-left text-xs font-medium text-muted-foreground px-4 py-3"},"Status"),t("th",{class:"text-left text-xs font-medium text-muted-foreground px-4 py-3"},"Joined")])],-1)),t("tbody",null,[(s(!0),r(g,null,k(i.value,e=>(s(),r("tr",{key:e.id,class:"border-b border-border last:border-0 hover:bg-muted/30"},[t("td",E,[t("p",F,a(e.username),1)]),t("td",R,a(e.email),1),t("td",U,[n(x,{variant:e.role==="admin"?"default":"secondary",class:"text-xs"},{default:d(()=>[m(a(e.role),1)]),_:2},1032,["variant"])]),t("td",j,[n(x,{variant:e.is_active?"success":"outline",class:"text-xs"},{default:d(()=>[m(a(e.is_active?"Active":"Inactive"),1)]),_:2},1032,["variant"])]),t("td",I,a(A($)(e.created_at)),1)]))),128))])])]),_:1})]),_:1}))]))}});export{G as default}; diff --git a/src/static/assets/AdminView-DUmZvUGQ.js b/src/static/assets/AdminView-DUmZvUGQ.js new file mode 100644 index 0000000..f186a3e --- /dev/null +++ b/src/static/assets/AdminView-DUmZvUGQ.js @@ -0,0 +1 @@ +import{d as _,u as y,v as h,c as r,a as t,e as n,k as v,w as d,f as b,q as m,o as s,F as g,r as k,t as a,p as u,h as A}from"./index-DzSm5_bv.js";import{a as w}from"./admin-DOjSzxjn.js";import{_ as B,a as S}from"./CardContent.vue_vue_type_script_setup_true_lang-B899D1fp.js";import{_ as f}from"./Badge.vue_vue_type_script_setup_true_lang-CaB6FyQ0.js";import{_ as V}from"./Spinner.vue_vue_type_script_setup_true_lang-DxuuceC3.js";import{a as $}from"./utils-7WVCegLb.js";const N={class:"p-6"},C={key:0,class:"flex items-center justify-center h-20"},D={class:"w-full"},E={class:"px-4 py-3"},F={class:"text-sm font-medium text-foreground"},R={class:"px-4 py-3 text-sm text-muted-foreground"},U={class:"px-4 py-3"},j={class:"px-4 py-3"},q={class:"px-4 py-3 text-xs text-muted-foreground"},H=_({__name:"AdminView",setup(I){const x=y(),p=b(),i=m([]),l=m(!1);return h(async()=>{if(!x.isAdmin){p.push("/");return}l.value=!0;try{const c=await w.users();i.value=c.data}finally{l.value=!1}}),(c,o)=>(s(),r("div",N,[o[1]||(o[1]=t("h2",{class:"text-lg font-semibold text-foreground mb-6"},"Admin — Users",-1)),l.value?(s(),r("div",C,[n(V,{class:"text-primary"})])):(s(),v(B,{key:1},{default:d(()=>[n(S,{class:"p-0"},{default:d(()=>[t("table",D,[o[0]||(o[0]=t("thead",null,[t("tr",{class:"border-b border-border"},[t("th",{class:"text-left text-xs font-medium text-muted-foreground px-4 py-3"},"User"),t("th",{class:"text-left text-xs font-medium text-muted-foreground px-4 py-3"},"Email"),t("th",{class:"text-left text-xs font-medium text-muted-foreground px-4 py-3"},"Role"),t("th",{class:"text-left text-xs font-medium text-muted-foreground px-4 py-3"},"Status"),t("th",{class:"text-left text-xs font-medium text-muted-foreground px-4 py-3"},"Joined")])],-1)),t("tbody",null,[(s(!0),r(g,null,k(i.value,e=>(s(),r("tr",{key:e.id,class:"border-b border-border last:border-0 hover:bg-muted/30"},[t("td",E,[t("p",F,a(e.username),1)]),t("td",R,a(e.email),1),t("td",U,[n(f,{variant:e.role==="admin"?"default":"secondary",class:"text-xs"},{default:d(()=>[u(a(e.role),1)]),_:2},1032,["variant"])]),t("td",j,[n(f,{variant:e.is_active?"success":"outline",class:"text-xs"},{default:d(()=>[u(a(e.is_active?"Active":"Inactive"),1)]),_:2},1032,["variant"])]),t("td",q,a(A($)(e.created_at)),1)]))),128))])])]),_:1})]),_:1}))]))}});export{H as default}; diff --git a/src/static/assets/AppLayout-J7i4Eomh.js b/src/static/assets/AppLayout-J7i4Eomh.js deleted file mode 100644 index be79b36..0000000 --- a/src/static/assets/AppLayout-J7i4Eomh.js +++ /dev/null @@ -1 +0,0 @@ -import{d as M,u as j,c as s,b as V,a as e,F as $,l as A,t as m,i as h,m as b,o as n,n as H,w as _,j as C,p as d,q as B,g as z,s as S,k as D,K as T,f as L,e as x,T as R,r as O}from"./index-yrXqsixb.js";const I={class:"flex flex-col h-full bg-[hsl(220_44%_8%)] border-r border-border"},P={class:"flex-1 px-2 py-3 space-y-0.5 overflow-y-auto"},N={key:0,class:"absolute left-0 top-1/2 -translate-y-1/2 w-0.5 h-4 bg-primary rounded-r-full"},F={class:"text-sm"},K={class:"p-3 border-t border-border shrink-0"},q={class:"flex items-center gap-3 px-2 py-2 rounded-lg"},E={class:"h-7 w-7 rounded-full bg-primary/15 ring-1 ring-primary/20 flex items-center justify-center text-[10px] font-bold text-primary shrink-0"},U={class:"flex-1 min-w-0"},W={class:"text-xs font-medium text-foreground truncate"},G=M({__name:"Sidebar",emits:["close"],setup(y,{emit:g}){const a=z(),l=j(),v=g,u=[{name:"Dashboard",path:"/",icon:"grid"},{name:"Calendar",path:"/calendar",icon:"calendar"},{name:"Planner",path:"/planner",icon:"check-square"},{name:"Projects",path:"/projects",icon:"folder"},{name:"Live Feed",path:"/live",icon:"activity"},{name:"Reports",path:"/reports",icon:"file-text"},{name:"Keys",path:"/keys",icon:"key"},{name:"DevOps",path:"/devops",icon:"devops"},{name:"Settings",path:"/settings",icon:"settings"},{name:"Admin",path:"/admin",icon:"shield",adminOnly:!0}],f=b(()=>u.filter(c=>!c.adminOnly||l.isAdmin));function r(c){return c==="/"?a.path==="/":a.path.startsWith(c)}const i=b(()=>{var t,p;return(((t=l.user)==null?void 0:t.username)??((p=l.user)==null?void 0:p.email)??"?").slice(0,2).toUpperCase()});return(c,t)=>{var k,w;const p=B("RouterLink");return n(),s("aside",I,[t[12]||(t[12]=V('
CC Dashboard
Oliver Agency
CC Dashboard
Oliver Agency
Corporate Planning Hub
Corporate Planning Hub
'+(n?t:m(t,!0))+`
`:""+(n?t:m(t,!0))+`
`}blockquote(t){return`@@ -41,6 +41,6 @@ ${t}`}tablerow(t){return`
${t}`}br(){return"An error occurred:
"+m(n.message+"",!0)+"";return e?Promise.resolve(i):i}if(e)return Promise.reject(n);throw n}};const R=new Rt;function g(a,t){return R.parse(a,t)}g.options=g.setOptions=function(a){return R.setOptions(a),g.defaults=R.defaults,we(g.defaults),g};g.getDefaults=J;g.defaults=S;g.use=function(...a){return R.use(...a),g.defaults=R.defaults,we(g.defaults),g};g.walkTokens=function(a,t){return R.walkTokens(a,t)};g.parseInline=R.parseInline;g.Parser=y;g.parser=y.parse;g.Renderer=N;g.TextRenderer=ie;g.Lexer=w;g.lexer=w.lex;g.Tokenizer=Q;g.Hooks=L;g.parse=g;g.options;g.setOptions;g.use;g.walkTokens;g.parseInline;y.parse;w.lex;const vt={class:"p-6"},St={class:"flex items-center gap-3 mb-6 flex-wrap"},It={class:"flex items-center gap-2"},At={class:"flex items-center rounded-md border border-border overflow-hidden"},Ct={key:0,class:"flex items-center justify-center h-20"},Et={key:1,class:"text-center text-muted-foreground py-12 text-sm"},Lt={key:2,class:"space-y-3"},Bt=["onClick"],qt={class:"flex items-center gap-2 flex-wrap"},Zt={class:"text-sm font-medium text-foreground"},Pt={class:"flex items-center gap-2 shrink-0"},Dt={class:"text-xs text-muted-foreground"},Mt={key:0,class:"mt-4 pt-4 border-t border-border"},Qt=["innerHTML"],jt=Be({__name:"ReportsView",setup(a){const t=A([]),e=A(!1),n=A(!1),i=A(null),r=A("daily");qe(()=>s());async function s(){e.value=!0;try{const c=await ge.list();t.value=c.data}finally{e.value=!1}}async function l(){n.value=!0;try{await ge.generate({type:r.value,period_date:Fe(new Date)}),ue.success("Report generated"),await s()}catch{ue.error("Failed to generate report")}finally{n.value=!1}}function o(c){i.value=i.value===c?null:c}function u(c){return g(c)}return(c,h)=>($(),z("div",vt,[x("div",St,[h[3]||(h[3]=x("h2",{class:"text-lg font-semibold text-foreground flex-1"},"AI Reports",-1)),x("div",It,[x("div",At,[x("button",{class:U(["px-3 py-1.5 text-xs font-medium transition-colors",r.value==="daily"?"bg-primary text-primary-foreground":"text-muted-foreground hover:bg-muted"]),onClick:h[0]||(h[0]=p=>r.value="daily")},"Daily",2),x("button",{class:U(["px-3 py-1.5 text-xs font-medium transition-colors",r.value==="weekly"?"bg-primary text-primary-foreground":"text-muted-foreground hover:bg-muted"]),onClick:h[1]||(h[1]=p=>r.value="weekly")},"Weekly",2)]),P(Ne,{size:"sm",loading:n.value,onClick:l},{default:I(()=>[...h[2]||(h[2]=[G(" Generate Now ",-1)])]),_:1},8,["loading"])])]),e.value?($(),z("div",Ct,[P(Oe,{class:"text-primary"})])):t.value.length===0?($(),z("div",Et," No reports generated yet ")):($(),z("div",Lt,[($(!0),z(Ze,null,Pe(t.value,p=>($(),pe(je,{key:p.id},{default:I(()=>[P(Qe,{class:"p-4"},{default:I(()=>[x("div",{class:"flex items-start justify-between gap-3 cursor-pointer",onClick:f=>o(p.id)},[x("div",qt,[P(fe,{variant:p.type==="daily"?"default":"secondary",class:"text-xs"},{default:I(()=>[G(W(p.type),1)]),_:2},1032,["variant"]),x("span",Zt,W(De(He)(p.period_date)),1),p.email_sent?($(),pe(fe,{key:0,variant:"success",class:"text-xs"},{default:I(()=>[...h[4]||(h[4]=[G(" Email sent ",-1)])]),_:1})):he("",!0)]),x("div",Pt,[x("span",Dt,W(new Date(p.generated_at).toLocaleString()),1),($(),z("svg",{class:U(["h-4 w-4 text-muted-foreground transition-transform",i.value===p.id?"rotate-180":""]),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[...h[5]||(h[5]=[x("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M19 9l-7 7-7-7"},null,-1)])],2))])],8,Bt),i.value===p.id?($(),z("div",Mt,[x("div",{class:"prose prose-sm prose-invert max-w-none text-sm text-foreground",innerHTML:u(p.content_markdown)},null,8,Qt)])):he("",!0)]),_:2},1024)]),_:2},1024))),128))]))]))}}),Gt=Me(jt,[["__scopeId","data-v-f60763ad"]]);export{Gt as default}; +`}strong(t){return`${t}`}em(t){return`${t}`}codespan(t){return`
${t}`}br(){return"An error occurred:
"+m(n.message+"",!0)+"";return e?Promise.resolve(i):i}if(e)return Promise.reject(n);throw n}};const R=new Rt;function g(a,t){return R.parse(a,t)}g.options=g.setOptions=function(a){return R.setOptions(a),g.defaults=R.defaults,we(g.defaults),g};g.getDefaults=J;g.defaults=S;g.use=function(...a){return R.use(...a),g.defaults=R.defaults,we(g.defaults),g};g.walkTokens=function(a,t){return R.walkTokens(a,t)};g.parseInline=R.parseInline;g.Parser=y;g.parser=y.parse;g.Renderer=j;g.TextRenderer=ie;g.Lexer=w;g.lexer=w.lex;g.Tokenizer=Q;g.Hooks=L;g.parse=g;g.options;g.setOptions;g.use;g.walkTokens;g.parseInline;y.parse;w.lex;const vt={class:"p-6"},St={class:"flex items-center gap-3 mb-6 flex-wrap"},It={class:"flex items-center gap-2"},At={class:"flex items-center rounded-md border border-border overflow-hidden"},Ct={key:0,class:"flex items-center justify-center h-20"},Et={key:1,class:"text-center text-muted-foreground py-12 text-sm"},Lt={key:2,class:"space-y-3"},Bt=["onClick"],qt={class:"flex items-center gap-2 flex-wrap"},Zt={class:"text-sm font-medium text-foreground"},Pt={class:"flex items-center gap-2 shrink-0"},Dt={class:"text-xs text-muted-foreground"},Mt={key:0,class:"mt-4 pt-4 border-t border-border"},Qt=["innerHTML"],Nt=Be({__name:"ReportsView",setup(a){const t=A([]),e=A(!1),n=A(!1),i=A(null),r=A("daily");qe(()=>s());async function s(){e.value=!0;try{const c=await ge.list();t.value=c.data}finally{e.value=!1}}async function l(){n.value=!0;try{await ge.generate({type:r.value,period_date:Fe(new Date)}),ue.success("Report generated"),await s()}catch{ue.error("Failed to generate report")}finally{n.value=!1}}function o(c){i.value=i.value===c?null:c}function u(c){return g(c)}return(c,h)=>($(),z("div",vt,[x("div",St,[h[3]||(h[3]=x("h2",{class:"text-lg font-semibold text-foreground flex-1"},"AI Reports",-1)),x("div",It,[x("div",At,[x("button",{class:U(["px-3 py-1.5 text-xs font-medium transition-colors",r.value==="daily"?"bg-primary text-primary-foreground":"text-muted-foreground hover:bg-muted"]),onClick:h[0]||(h[0]=p=>r.value="daily")},"Daily",2),x("button",{class:U(["px-3 py-1.5 text-xs font-medium transition-colors",r.value==="weekly"?"bg-primary text-primary-foreground":"text-muted-foreground hover:bg-muted"]),onClick:h[1]||(h[1]=p=>r.value="weekly")},"Weekly",2)]),P(je,{size:"sm",loading:n.value,onClick:l},{default:I(()=>[...h[2]||(h[2]=[G(" Generate Now ",-1)])]),_:1},8,["loading"])])]),e.value?($(),z("div",Ct,[P(Oe,{class:"text-primary"})])):t.value.length===0?($(),z("div",Et," No reports generated yet ")):($(),z("div",Lt,[($(!0),z(Ze,null,Pe(t.value,p=>($(),pe(Ne,{key:p.id},{default:I(()=>[P(Qe,{class:"p-4"},{default:I(()=>[x("div",{class:"flex items-start justify-between gap-3 cursor-pointer",onClick:f=>o(p.id)},[x("div",qt,[P(fe,{variant:p.type==="daily"?"default":"secondary",class:"text-xs"},{default:I(()=>[G(W(p.type),1)]),_:2},1032,["variant"]),x("span",Zt,W(De(He)(p.period_date)),1),p.email_sent?($(),pe(fe,{key:0,variant:"success",class:"text-xs"},{default:I(()=>[...h[4]||(h[4]=[G(" Email sent ",-1)])]),_:1})):he("",!0)]),x("div",Pt,[x("span",Dt,W(new Date(p.generated_at).toLocaleString()),1),($(),z("svg",{class:U(["h-4 w-4 text-muted-foreground transition-transform",i.value===p.id?"rotate-180":""]),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[...h[5]||(h[5]=[x("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M19 9l-7 7-7-7"},null,-1)])],2))])],8,Bt),i.value===p.id?($(),z("div",Mt,[x("div",{class:"prose prose-sm prose-invert max-w-none text-sm text-foreground",innerHTML:u(p.content_markdown)},null,8,Qt)])):he("",!0)]),_:2},1024)]),_:2},1024))),128))]))]))}}),Wt=Me(Nt,[["__scopeId","data-v-f60763ad"]]);export{Wt as default}; diff --git a/src/static/assets/SettingsView-BXkPmh00.js b/src/static/assets/SettingsView-BXkPmh00.js deleted file mode 100644 index f352b6b..0000000 --- a/src/static/assets/SettingsView-BXkPmh00.js +++ /dev/null @@ -1 +0,0 @@ -import{d as B,u as T,x as H,c as C,a,e as o,w as s,r as u,o as x,k as i,i as n,t as y,j as k,n as I,D as K,K as m}from"./index-yrXqsixb.js";import{u as L}from"./devops-C_7zqRan.js";import{_ as A,a as P}from"./CardContent.vue_vue_type_script_setup_true_lang-BZS0eQer.js";import{_ as U,a as z}from"./CardTitle.vue_vue_type_script_setup_true_lang-Bs99oJeq.js";import{_ as f}from"./Input.vue_vue_type_script_setup_true_lang-Bo0JoDsF.js";import{_}from"./Button.vue_vue_type_script_setup_true_lang-XMbqbqq8.js";import{i as j}from"./utils-D_0J15Md.js";function M(v,d){const t=`/cc-dashboard/api/export/timesheet.csv?from=${v}&to=${d}`,r=document.createElement("a");r.href=t,r.download=`timesheet-${v}-${d}.csv`,r.click()}function q(v,d){const t=`/cc-dashboard/api/export/timesheet.ics?from=${v}&to=${d}`,r=document.createElement("a");r.href=t,r.download=`timesheet-${v}-${d}.ics`,r.click()}const G={class:"p-6 space-y-6 max-w-2xl"},J={class:"space-y-1.5"},Q={class:"space-y-1.5"},R={key:0,class:"text-xs text-muted-foreground space-y-1"},W={class:"text-foreground"},X={class:"text-foreground"},Y={key:0},Z={key:1,class:"text-red-400"},h={class:"grid grid-cols-2 gap-3"},ee={class:"space-y-1.5"},te={class:"space-y-1.5"},ae={class:"space-y-1.5"},oe={class:"text-sm font-medium text-foreground"},se={class:"flex items-center gap-2"},le={class:"flex items-center gap-3 flex-wrap"},ne={class:"space-y-1.5"},re={class:"space-y-1.5"},ie={class:"flex items-center gap-2"},ge=B({__name:"SettingsView",setup(v){const d=T(),t=L(),r=u(""),D=u(0),S=u(!1),c=u(""),p=u(""),g=u(""),b=u(!1),V=u(""),w=u("");H(()=>{d.user&&(r.value=d.user.username,D.value=d.user.daily_overhead_hours??0),t.fetchIntegration().then(()=>{t.integration&&(c.value=t.integration.organization,p.value=t.integration.project)});const $=new Date;w.value=j($);const e=new Date($);e.setDate($.getDate()-30),V.value=j(e)});async function O(){S.value=!0;try{await K.patch("/api/auth/me",{username:r.value,daily_overhead_hours:D.value}),await d.fetchMe(),m.success("Profile saved")}catch{m.error("Failed to save profile")}finally{S.value=!1}}async function N(){if(!c.value||!p.value||!g.value){m.error("All ADO fields are required");return}b.value=!0;try{await t.saveIntegration({organization:c.value,project:p.value,pat:g.value}),g.value="",m.success("Integration saved")}catch{m.error("Failed to save integration")}finally{b.value=!1}}async function E(){if(confirm("Delete ADO integration?"))try{await t.deleteIntegration(),c.value="",p.value="",g.value="",m.success("Integration deleted")}catch{m.error("Failed to delete integration")}}async function F(){try{await t.sync(),m.success("Sync complete")}catch{m.error(t.error??"Sync failed")}}return($,e)=>(x(),C("div",G,[e[26]||(e[26]=a("h2",{class:"text-lg font-semibold text-foreground"},"Settings",-1)),o(A,null,{default:s(()=>[o(U,null,{default:s(()=>[o(z,{class:"text-sm"},{default:s(()=>[...e[9]||(e[9]=[i("Profile",-1)])]),_:1})]),_:1}),o(P,{class:"space-y-4"},{default:s(()=>[a("div",J,[e[10]||(e[10]=a("label",{class:"text-sm font-medium text-foreground"},"Username",-1)),o(f,{modelValue:r.value,"onUpdate:modelValue":e[0]||(e[0]=l=>r.value=l),placeholder:"username"},null,8,["modelValue"])]),a("div",Q,[e[11]||(e[11]=a("label",{class:"text-sm font-medium text-foreground"},"Daily Overhead Hours",-1)),o(f,{modelValue:D.value,"onUpdate:modelValue":e[1]||(e[1]=l=>D.value=l),type:"number",min:"0",max:"8",step:"0.25",class:"w-32"},null,8,["modelValue"]),e[12]||(e[12]=a("p",{class:"text-xs text-muted-foreground"}," Hours per day to add for overhead / meetings ",-1))]),o(_,{loading:S.value,onClick:O},{default:s(()=>[...e[13]||(e[13]=[i("Save Profile",-1)])]),_:1},8,["loading"])]),_:1})]),_:1}),o(A,null,{default:s(()=>[o(U,null,{default:s(()=>[o(z,{class:"text-sm"},{default:s(()=>[...e[14]||(e[14]=[i("Azure DevOps Integration",-1)])]),_:1})]),_:1}),o(P,{class:"space-y-4"},{default:s(()=>[n(t).integration?(x(),C("div",R,[a("p",null,[e[15]||(e[15]=i(" Connected to ",-1)),a("strong",W,y(n(t).integration.organization),1),e[16]||(e[16]=i(" / ",-1)),a("strong",X,y(n(t).integration.project),1)]),n(t).integration.last_synced_at?(x(),C("p",Y," Last synced: "+y(new Date(n(t).integration.last_synced_at).toLocaleString()),1)):k("",!0),n(t).integration.last_sync_error?(x(),C("p",Z," Error: "+y(n(t).integration.last_sync_error),1)):k("",!0)])):k("",!0),a("div",h,[a("div",ee,[e[17]||(e[17]=a("label",{class:"text-sm font-medium text-foreground"},"Organization",-1)),o(f,{modelValue:c.value,"onUpdate:modelValue":e[2]||(e[2]=l=>c.value=l),placeholder:"myorg"},null,8,["modelValue"])]),a("div",te,[e[18]||(e[18]=a("label",{class:"text-sm font-medium text-foreground"},"Project",-1)),o(f,{modelValue:p.value,"onUpdate:modelValue":e[3]||(e[3]=l=>p.value=l),placeholder:"myproject"},null,8,["modelValue"])])]),a("div",ae,[a("label",oe," Personal Access Token "+y(n(t).integration?"(leave blank to keep current)":""),1),o(f,{modelValue:g.value,"onUpdate:modelValue":e[4]||(e[4]=l=>g.value=l),type:"password",placeholder:"••••••••",autocomplete:"new-password"},null,8,["modelValue"])]),a("div",se,[o(_,{loading:b.value,onClick:N},{default:s(()=>[i(y(n(t).integration?"Update":"Connect"),1)]),_:1},8,["loading"]),n(t).integration?(x(),I(_,{key:0,variant:"outline",loading:n(t).syncing,onClick:F},{default:s(()=>[...e[19]||(e[19]=[i(" Sync Now ",-1)])]),_:1},8,["loading"])):k("",!0),n(t).integration?(x(),I(_,{key:1,variant:"destructive",size:"sm",onClick:E},{default:s(()=>[...e[20]||(e[20]=[i(" Disconnect ",-1)])]),_:1})):k("",!0)])]),_:1})]),_:1}),o(A,null,{default:s(()=>[o(U,null,{default:s(()=>[o(z,{class:"text-sm"},{default:s(()=>[...e[21]||(e[21]=[i("Export",-1)])]),_:1})]),_:1}),o(P,{class:"space-y-4"},{default:s(()=>[a("div",le,[a("div",ne,[e[22]||(e[22]=a("label",{class:"text-xs text-muted-foreground"},"From",-1)),o(f,{modelValue:V.value,"onUpdate:modelValue":e[5]||(e[5]=l=>V.value=l),type:"date",class:"h-8 text-xs"},null,8,["modelValue"])]),a("div",re,[e[23]||(e[23]=a("label",{class:"text-xs text-muted-foreground"},"To",-1)),o(f,{modelValue:w.value,"onUpdate:modelValue":e[6]||(e[6]=l=>w.value=l),type:"date",class:"h-8 text-xs"},null,8,["modelValue"])])]),a("div",ie,[o(_,{variant:"outline",size:"sm",onClick:e[7]||(e[7]=l=>n(M)(V.value,w.value))},{default:s(()=>[...e[24]||(e[24]=[i(" Download CSV ",-1)])]),_:1}),o(_,{variant:"outline",size:"sm",onClick:e[8]||(e[8]=l=>n(q)(V.value,w.value))},{default:s(()=>[...e[25]||(e[25]=[i(" Download ICS ",-1)])]),_:1})])]),_:1})]),_:1})]))}});export{ge as default}; diff --git a/src/static/assets/SettingsView-DsEb6gx-.js b/src/static/assets/SettingsView-DsEb6gx-.js new file mode 100644 index 0000000..bcefab8 --- /dev/null +++ b/src/static/assets/SettingsView-DsEb6gx-.js @@ -0,0 +1 @@ +import{d as B,u as T,v as q,c as C,a,e as o,w as s,q as u,o as x,p as i,h as n,t as y,i as k,k as I,D as H,K as m}from"./index-DzSm5_bv.js";import{u as K}from"./devops-S5lsRUq3.js";import{_ as A,a as P}from"./CardContent.vue_vue_type_script_setup_true_lang-B899D1fp.js";import{_ as U,a as z}from"./CardTitle.vue_vue_type_script_setup_true_lang-ByUGRP-t.js";import{_ as f}from"./Input.vue_vue_type_script_setup_true_lang-DX_izdWK.js";import{_}from"./Button.vue_vue_type_script_setup_true_lang-D97aKlXO.js";import{i as O}from"./utils-7WVCegLb.js";import"./Spinner.vue_vue_type_script_setup_true_lang-DxuuceC3.js";function L(v,d){const t=`/cc-dashboard/api/export/timesheet.csv?from=${v}&to=${d}`,r=document.createElement("a");r.href=t,r.download=`timesheet-${v}-${d}.csv`,r.click()}function M(v,d){const t=`/cc-dashboard/api/export/timesheet.ics?from=${v}&to=${d}`,r=document.createElement("a");r.href=t,r.download=`timesheet-${v}-${d}.ics`,r.click()}const h={class:"p-6 space-y-6 max-w-2xl"},G={class:"space-y-1.5"},J={class:"space-y-1.5"},Q={key:0,class:"text-xs text-muted-foreground space-y-1"},R={class:"text-foreground"},W={class:"text-foreground"},X={key:0},Y={key:1,class:"text-red-400"},Z={class:"grid grid-cols-2 gap-3"},ee={class:"space-y-1.5"},te={class:"space-y-1.5"},ae={class:"space-y-1.5"},oe={class:"text-sm font-medium text-foreground"},se={class:"flex items-center gap-2"},le={class:"flex items-center gap-3 flex-wrap"},ne={class:"space-y-1.5"},re={class:"space-y-1.5"},ie={class:"flex items-center gap-2"},xe=B({__name:"SettingsView",setup(v){const d=T(),t=K(),r=u(""),D=u(0),S=u(!1),c=u(""),p=u(""),g=u(""),b=u(!1),V=u(""),w=u("");q(()=>{d.user&&(r.value=d.user.username,D.value=d.user.daily_overhead_hours??0),t.fetchIntegration().then(()=>{t.integration&&(c.value=t.integration.organization,p.value=t.integration.project)});const $=new Date;w.value=O($);const e=new Date($);e.setDate($.getDate()-30),V.value=O(e)});async function j(){S.value=!0;try{await H.patch("/api/auth/me",{username:r.value,daily_overhead_hours:D.value}),await d.fetchMe(),m.success("Profile saved")}catch{m.error("Failed to save profile")}finally{S.value=!1}}async function N(){if(!c.value||!p.value||!g.value){m.error("All ADO fields are required");return}b.value=!0;try{await t.saveIntegration({organization:c.value,project:p.value,pat:g.value}),g.value="",m.success("Integration saved")}catch{m.error("Failed to save integration")}finally{b.value=!1}}async function E(){if(confirm("Delete ADO integration?"))try{await t.deleteIntegration(),c.value="",p.value="",g.value="",m.success("Integration deleted")}catch{m.error("Failed to delete integration")}}async function F(){try{await t.sync(),m.success("Sync complete")}catch{m.error(t.error??"Sync failed")}}return($,e)=>(x(),C("div",h,[e[26]||(e[26]=a("h2",{class:"text-lg font-semibold text-foreground"},"Settings",-1)),o(A,null,{default:s(()=>[o(U,null,{default:s(()=>[o(z,{class:"text-sm"},{default:s(()=>[...e[9]||(e[9]=[i("Profile",-1)])]),_:1})]),_:1}),o(P,{class:"space-y-4"},{default:s(()=>[a("div",G,[e[10]||(e[10]=a("label",{class:"text-sm font-medium text-foreground"},"Username",-1)),o(f,{modelValue:r.value,"onUpdate:modelValue":e[0]||(e[0]=l=>r.value=l),placeholder:"username"},null,8,["modelValue"])]),a("div",J,[e[11]||(e[11]=a("label",{class:"text-sm font-medium text-foreground"},"Daily Overhead Hours",-1)),o(f,{modelValue:D.value,"onUpdate:modelValue":e[1]||(e[1]=l=>D.value=l),type:"number",min:"0",max:"8",step:"0.25",class:"w-32"},null,8,["modelValue"]),e[12]||(e[12]=a("p",{class:"text-xs text-muted-foreground"}," Hours per day to add for overhead / meetings ",-1))]),o(_,{loading:S.value,onClick:j},{default:s(()=>[...e[13]||(e[13]=[i("Save Profile",-1)])]),_:1},8,["loading"])]),_:1})]),_:1}),o(A,null,{default:s(()=>[o(U,null,{default:s(()=>[o(z,{class:"text-sm"},{default:s(()=>[...e[14]||(e[14]=[i("Azure DevOps Integration",-1)])]),_:1})]),_:1}),o(P,{class:"space-y-4"},{default:s(()=>[n(t).integration?(x(),C("div",Q,[a("p",null,[e[15]||(e[15]=i(" Connected to ",-1)),a("strong",R,y(n(t).integration.organization),1),e[16]||(e[16]=i(" / ",-1)),a("strong",W,y(n(t).integration.project),1)]),n(t).integration.last_synced_at?(x(),C("p",X," Last synced: "+y(new Date(n(t).integration.last_synced_at).toLocaleString()),1)):k("",!0),n(t).integration.last_sync_error?(x(),C("p",Y," Error: "+y(n(t).integration.last_sync_error),1)):k("",!0)])):k("",!0),a("div",Z,[a("div",ee,[e[17]||(e[17]=a("label",{class:"text-sm font-medium text-foreground"},"Organization",-1)),o(f,{modelValue:c.value,"onUpdate:modelValue":e[2]||(e[2]=l=>c.value=l),placeholder:"myorg"},null,8,["modelValue"])]),a("div",te,[e[18]||(e[18]=a("label",{class:"text-sm font-medium text-foreground"},"Project",-1)),o(f,{modelValue:p.value,"onUpdate:modelValue":e[3]||(e[3]=l=>p.value=l),placeholder:"myproject"},null,8,["modelValue"])])]),a("div",ae,[a("label",oe," Personal Access Token "+y(n(t).integration?"(leave blank to keep current)":""),1),o(f,{modelValue:g.value,"onUpdate:modelValue":e[4]||(e[4]=l=>g.value=l),type:"password",placeholder:"••••••••",autocomplete:"new-password"},null,8,["modelValue"])]),a("div",se,[o(_,{loading:b.value,onClick:N},{default:s(()=>[i(y(n(t).integration?"Update":"Connect"),1)]),_:1},8,["loading"]),n(t).integration?(x(),I(_,{key:0,variant:"outline",loading:n(t).syncing,onClick:F},{default:s(()=>[...e[19]||(e[19]=[i(" Sync Now ",-1)])]),_:1},8,["loading"])):k("",!0),n(t).integration?(x(),I(_,{key:1,variant:"destructive",size:"sm",onClick:E},{default:s(()=>[...e[20]||(e[20]=[i(" Disconnect ",-1)])]),_:1})):k("",!0)])]),_:1})]),_:1}),o(A,null,{default:s(()=>[o(U,null,{default:s(()=>[o(z,{class:"text-sm"},{default:s(()=>[...e[21]||(e[21]=[i("Export",-1)])]),_:1})]),_:1}),o(P,{class:"space-y-4"},{default:s(()=>[a("div",le,[a("div",ne,[e[22]||(e[22]=a("label",{class:"text-xs text-muted-foreground"},"From",-1)),o(f,{modelValue:V.value,"onUpdate:modelValue":e[5]||(e[5]=l=>V.value=l),type:"date",class:"h-8 text-xs"},null,8,["modelValue"])]),a("div",re,[e[23]||(e[23]=a("label",{class:"text-xs text-muted-foreground"},"To",-1)),o(f,{modelValue:w.value,"onUpdate:modelValue":e[6]||(e[6]=l=>w.value=l),type:"date",class:"h-8 text-xs"},null,8,["modelValue"])])]),a("div",ie,[o(_,{variant:"outline",size:"sm",onClick:e[7]||(e[7]=l=>n(L)(V.value,w.value))},{default:s(()=>[...e[24]||(e[24]=[i(" Download CSV ",-1)])]),_:1}),o(_,{variant:"outline",size:"sm",onClick:e[8]||(e[8]=l=>n(M)(V.value,w.value))},{default:s(()=>[...e[25]||(e[25]=[i(" Download ICS ",-1)])]),_:1})])]),_:1})]),_:1})]))}});export{xe as default}; diff --git a/src/static/assets/Spinner.vue_vue_type_script_setup_true_lang-DxuuceC3.js b/src/static/assets/Spinner.vue_vue_type_script_setup_true_lang-DxuuceC3.js new file mode 100644 index 0000000..11b25d1 --- /dev/null +++ b/src/static/assets/Spinner.vue_vue_type_script_setup_true_lang-DxuuceC3.js @@ -0,0 +1 @@ +import{d as l,o as n,c as o,n as t,a as r}from"./index-DzSm5_bv.js";const i=l({__name:"Spinner",props:{size:{},class:{}},setup(s){return(a,e)=>(n(),o("svg",{class:t(["animate-spin text-current",s.size==="sm"?"h-3 w-3":s.size==="lg"?"h-6 w-6":"h-4 w-4",a.$props.class]),xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24"},[...e[0]||(e[0]=[r("circle",{class:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor","stroke-width":"4"},null,-1),r("path",{class:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"},null,-1)])],2))}});export{i as _}; diff --git a/src/static/assets/TaskForm.vue_vue_type_script_setup_true_lang-CuS-8amU.js b/src/static/assets/TaskForm.vue_vue_type_script_setup_true_lang-Dq5zJejp.js similarity index 85% rename from src/static/assets/TaskForm.vue_vue_type_script_setup_true_lang-CuS-8amU.js rename to src/static/assets/TaskForm.vue_vue_type_script_setup_true_lang-Dq5zJejp.js index 29b4202..2e62943 100644 --- a/src/static/assets/TaskForm.vue_vue_type_script_setup_true_lang-CuS-8amU.js +++ b/src/static/assets/TaskForm.vue_vue_type_script_setup_true_lang-Dq5zJejp.js @@ -1 +1 @@ -import{D as v,B as I,r as _,d as D,o as k,c as g,p as N,i as w,t as V,j as C,s as A,x as E,v as L,n as M,w as y,a as s,e as r,k as h,F as z,l as T,h as O}from"./index-yrXqsixb.js";import{_ as W}from"./Dialog.vue_vue_type_script_setup_true_lang-Bjx8yW8V.js";import{_ as $}from"./Input.vue_vue_type_script_setup_true_lang-Bo0JoDsF.js";import{c as F}from"./utils-D_0J15Md.js";import{_ as U}from"./Button.vue_vue_type_script_setup_true_lang-XMbqbqq8.js";import{u as H}from"./devops-C_7zqRan.js";const b={list:t=>v.get("/api/tasks",{params:t}),get:t=>v.get(`/api/tasks/${t}`),create:t=>v.post("/api/tasks",t),update:(t,d)=>v.patch(`/api/tasks/${t}`,d),remove:t=>v.delete(`/api/tasks/${t}`),complete:t=>v.post(`/api/tasks/${t}/complete`),blocks:t=>v.get(`/api/tasks/${t}/blocks`),createBlock:(t,d)=>v.post(`/api/tasks/${t}/blocks`,d),updateBlock:(t,d)=>v.patch(`/api/tasks/blocks/${t}`,d),deleteBlock:t=>v.delete(`/api/tasks/blocks/${t}`)},ge=I("tasks",()=>{const t=_([]),d=_(!1),o=_(null);async function m(i){d.value=!0,o.value=null;try{const n=await b.list({date:i});t.value=n.data}catch(n){const c=n;o.value=c.message??"Failed to fetch tasks"}finally{d.value=!1}}async function f(i){d.value=!0,o.value=null;try{const n=await b.list(i?{project_id:i}:void 0);t.value=n.data}catch(n){const c=n;o.value=c.message??"Failed to fetch tasks"}finally{d.value=!1}}async function p(i){const n=await b.create(i);return t.value.push(n.data),n.data}async function a(i,n){const c=await b.update(i,n),S=t.value.findIndex(P=>P.id===i);return S!==-1&&(t.value[S]=c.data),c.data}async function u(i){await b.remove(i),t.value=t.value.filter(n=>n.id!==i)}async function j(i){const n=await b.complete(i),c=t.value.findIndex(S=>S.id===i);return c!==-1&&(t.value[c]=n.data),n.data}async function x(i,n){return(await b.createBlock(i,n)).data}async function e(i,n){return(await b.updateBlock(i,n)).data}async function l(i){await b.deleteBlock(i)}return{tasks:t,loading:d,error:o,fetchForDate:m,fetchAll:f,create:p,update:a,remove:u,complete:j,createBlock:x,updateBlock:e,deleteBlock:l}}),q=["id","value","placeholder","disabled","rows"],G=D({__name:"Textarea",props:{modelValue:{},placeholder:{},disabled:{type:Boolean},rows:{},class:{},id:{}},emits:["update:modelValue"],setup(t,{emit:d}){const o=t,m=d;return(f,p)=>(k(),g("textarea",{id:t.id,value:t.modelValue,placeholder:t.placeholder,disabled:t.disabled,rows:t.rows??3,class:N(w(F)("flex w-full rounded-md border border-input bg-background px-3 py-2 text-sm","ring-offset-background placeholder:text-muted-foreground","focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2","disabled:cursor-not-allowed disabled:opacity-50 resize-none",o.class)),onInput:p[0]||(p[0]=a=>m("update:modelValue",a.target.value))},null,42,q))}}),J=["id","value","disabled"],K=["selected"],B=D({__name:"Select",props:{modelValue:{},disabled:{type:Boolean},class:{},id:{},placeholder:{}},emits:["update:modelValue","change"],setup(t,{emit:d}){const o=t,m=d;return(f,p)=>(k(),g("select",{id:t.id,value:t.modelValue,disabled:t.disabled,class:N(w(F)("flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm","ring-offset-background focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2","disabled:cursor-not-allowed disabled:opacity-50",o.class)),onChange:p[0]||(p[0]=a=>m("update:modelValue",a.target.value))},[t.placeholder?(k(),g("option",{key:0,value:"",disabled:"",selected:!t.modelValue},V(t.placeholder),9,K)):C("",!0),A(f.$slots,"default")],42,J))}}),Q={list:()=>v.get("/api/projects")},R=I("projects",()=>{const t=_([]),d=_(!1);async function o(){if(!(t.value.length>0)){d.value=!0;try{const m=await Q.list();t.value=m.data}catch{t.value=[]}finally{d.value=!1}}}return{projects:t,loading:d,fetchProjects:o}}),X={class:"space-y-1.5"},Y={class:"space-y-1.5"},Z={class:"grid grid-cols-2 gap-3"},ee={class:"space-y-1.5"},te={class:"space-y-1.5"},ae={class:"grid grid-cols-2 gap-3"},le={class:"space-y-1.5"},se={class:"space-y-1.5"},oe={class:"grid grid-cols-2 gap-3"},de={class:"space-y-1.5"},ie={class:"space-y-1.5"},ne={key:0,class:"space-y-1.5"},ue=["value"],re={key:1,class:"space-y-1.5"},me=["value"],ye=D({__name:"TaskForm",props:{open:{type:Boolean},task:{default:null},defaultDate:{}},emits:["close","save"],setup(t,{emit:d}){const o=t,m=d,f=H(),p=R();E(()=>{p.fetchProjects()});const a=_({title:"",notes:"",planned_date:"",start_time:"",end_time:"",estimate_hours:1,status:"todo",priority:3,project_id:void 0,azure_work_item_id:void 0});L(()=>o.open,x=>{x&&(o.task?a.value={title:o.task.title,notes:o.task.notes??"",planned_date:o.task.planned_date??"",start_time:"",end_time:"",estimate_hours:o.task.estimate_hours??1,status:o.task.status,priority:o.task.priority,project_id:o.task.project_id??void 0,azure_work_item_id:o.task.azure_work_item_id??void 0}:a.value={title:"",notes:"",planned_date:o.defaultDate??"",start_time:"",end_time:"",estimate_hours:1,status:"todo",priority:3,project_id:void 0,azure_work_item_id:void 0},f.integration&&!f.workItems.length&&f.fetchWorkItems("open"))},{immediate:!0});const u=_(!1);async function j(){if(a.value.title.trim()){u.value=!0;try{const x={title:a.value.title,notes:a.value.notes||void 0,planned_date:a.value.planned_date,estimate_hours:a.value.estimate_hours,status:a.value.status,priority:a.value.priority,project_id:a.value.project_id||null,azure_work_item_id:a.value.azure_work_item_id||null};let e;a.value.planned_date&&a.value.start_time&&a.value.end_time&&(e={start_at:new Date(`${a.value.planned_date}T${a.value.start_time}:00`).toISOString(),end_at:new Date(`${a.value.planned_date}T${a.value.end_time}:00`).toISOString()}),m("save",x,e)}finally{u.value=!1}}}return(x,e)=>(k(),M(W,{open:t.open,title:t.task?"Edit Task":"New Task","max-width":"max-w-md",onClose:e[11]||(e[11]=l=>m("close"))},{footer:y(()=>[r(U,{variant:"outline",disabled:u.value,onClick:e[10]||(e[10]=l=>m("close"))},{default:y(()=>[...e[25]||(e[25]=[h("Cancel",-1)])]),_:1},8,["disabled"]),r(U,{loading:u.value,onClick:j},{default:y(()=>[h(V(t.task?"Update":"Create"),1)]),_:1},8,["loading"])]),default:y(()=>[s("form",{class:"space-y-4",onSubmit:O(j,["prevent"])},[s("div",X,[e[12]||(e[12]=s("label",{class:"text-sm font-medium text-foreground"},"Title *",-1)),r($,{modelValue:a.value.title,"onUpdate:modelValue":e[0]||(e[0]=l=>a.value.title=l),placeholder:"Task title...",disabled:u.value},null,8,["modelValue","disabled"])]),s("div",Y,[e[13]||(e[13]=s("label",{class:"text-sm font-medium text-foreground"},"Notes",-1)),r(G,{modelValue:a.value.notes,"onUpdate:modelValue":e[1]||(e[1]=l=>a.value.notes=l),placeholder:"Additional notes...",disabled:u.value},null,8,["modelValue","disabled"])]),s("div",Z,[s("div",ee,[e[14]||(e[14]=s("label",{class:"text-sm font-medium text-foreground"},"Planned Date",-1)),r($,{modelValue:a.value.planned_date,"onUpdate:modelValue":e[2]||(e[2]=l=>a.value.planned_date=l),type:"date",disabled:u.value},null,8,["modelValue","disabled"])]),s("div",te,[e[15]||(e[15]=s("label",{class:"text-sm font-medium text-foreground"},"Estimate (h)",-1)),r($,{modelValue:a.value.estimate_hours,"onUpdate:modelValue":e[3]||(e[3]=l=>a.value.estimate_hours=l),type:"number",min:"0.25",max:"24",step:"0.25",disabled:u.value},null,8,["modelValue","disabled"])])]),s("div",ae,[s("div",le,[e[16]||(e[16]=s("label",{class:"text-sm font-medium text-foreground"},[h("Start time "),s("span",{class:"text-muted-foreground font-normal"},"(optional)")],-1)),r($,{modelValue:a.value.start_time,"onUpdate:modelValue":e[4]||(e[4]=l=>a.value.start_time=l),type:"time",disabled:u.value},null,8,["modelValue","disabled"])]),s("div",se,[e[17]||(e[17]=s("label",{class:"text-sm font-medium text-foreground"},"End time",-1)),r($,{modelValue:a.value.end_time,"onUpdate:modelValue":e[5]||(e[5]=l=>a.value.end_time=l),type:"time",disabled:u.value},null,8,["modelValue","disabled"])])]),s("div",oe,[s("div",de,[e[19]||(e[19]=s("label",{class:"text-sm font-medium text-foreground"},"Status",-1)),r(B,{modelValue:a.value.status,"onUpdate:modelValue":e[6]||(e[6]=l=>a.value.status=l),disabled:u.value},{default:y(()=>[...e[18]||(e[18]=[s("option",{value:"todo"},"Todo",-1),s("option",{value:"doing"},"Doing",-1),s("option",{value:"done"},"Done",-1),s("option",{value:"cancelled"},"Cancelled",-1)])]),_:1},8,["modelValue","disabled"])]),s("div",ie,[e[21]||(e[21]=s("label",{class:"text-sm font-medium text-foreground"},"Priority",-1)),r(B,{modelValue:a.value.priority,"onUpdate:modelValue":e[7]||(e[7]=l=>a.value.priority=l),disabled:u.value},{default:y(()=>[...e[20]||(e[20]=[s("option",{value:"1"},"1 - Low",-1),s("option",{value:"2"},"2 - Normal",-1),s("option",{value:"3"},"3 - Medium",-1),s("option",{value:"4"},"4 - High",-1),s("option",{value:"5"},"5 - Critical",-1)])]),_:1},8,["modelValue","disabled"])])]),w(p).projects.length?(k(),g("div",ne,[e[23]||(e[23]=s("label",{class:"text-sm font-medium text-foreground"},"Project",-1)),r(B,{modelValue:a.value.project_id,"onUpdate:modelValue":e[8]||(e[8]=l=>a.value.project_id=l),disabled:u.value,placeholder:"Select project..."},{default:y(()=>[e[22]||(e[22]=s("option",{value:""},"None",-1)),(k(!0),g(z,null,T(w(p).projects,l=>(k(),g("option",{key:l.id,value:l.id},V(l.display_name)+V(l.job_number?` (${l.job_number})`:""),9,ue))),128))]),_:1},8,["modelValue","disabled"])])):C("",!0),w(f).workItems.length?(k(),g("div",re,[e[24]||(e[24]=s("label",{class:"text-sm font-medium text-foreground"},"Azure DevOps Work Item",-1)),r(B,{modelValue:a.value.azure_work_item_id,"onUpdate:modelValue":e[9]||(e[9]=l=>a.value.azure_work_item_id=l),disabled:u.value,placeholder:"Link work item..."},{default:y(()=>[(k(!0),g(z,null,T(w(f).workItems,l=>(k(),g("option",{key:l.id,value:l.id}," #"+V(l.ado_id)+" – "+V(l.title),9,me))),128))]),_:1},8,["modelValue","disabled"])])):C("",!0)],32)]),_:1},8,["open","title"]))}});export{ye as _,ge as u}; +import{D as v,A as I,q as _,d as D,o as k,c as g,n as N,h as w,t as x,i as C,m as P,v as E,s as L,k as M,w as y,a as s,e as r,p as h,F as z,r as T,B as O}from"./index-DzSm5_bv.js";import{_ as W}from"./Dialog.vue_vue_type_script_setup_true_lang-Bpehdtti.js";import{_ as $}from"./Input.vue_vue_type_script_setup_true_lang-DX_izdWK.js";import{c as A}from"./utils-7WVCegLb.js";import{_ as U}from"./Button.vue_vue_type_script_setup_true_lang-D97aKlXO.js";import{u as q}from"./devops-S5lsRUq3.js";const b={list:t=>v.get("/api/tasks",{params:t}),get:t=>v.get(`/api/tasks/${t}`),create:t=>v.post("/api/tasks",t),update:(t,d)=>v.patch(`/api/tasks/${t}`,d),remove:t=>v.delete(`/api/tasks/${t}`),complete:t=>v.post(`/api/tasks/${t}/complete`),blocks:t=>v.get(`/api/tasks/${t}/blocks`),createBlock:(t,d)=>v.post(`/api/tasks/${t}/blocks`,d),updateBlock:(t,d)=>v.patch(`/api/tasks/blocks/${t}`,d),deleteBlock:t=>v.delete(`/api/tasks/blocks/${t}`)},ge=I("tasks",()=>{const t=_([]),d=_(!1),o=_(null);async function m(i){d.value=!0,o.value=null;try{const n=await b.list({date:i});t.value=n.data}catch(n){const c=n;o.value=c.message??"Failed to fetch tasks"}finally{d.value=!1}}async function f(i){d.value=!0,o.value=null;try{const n=await b.list(i?{project_id:i}:void 0);t.value=n.data}catch(n){const c=n;o.value=c.message??"Failed to fetch tasks"}finally{d.value=!1}}async function p(i){const n=await b.create(i);return t.value.push(n.data),n.data}async function a(i,n){const c=await b.update(i,n),S=t.value.findIndex(F=>F.id===i);return S!==-1&&(t.value[S]=c.data),c.data}async function u(i){await b.remove(i),t.value=t.value.filter(n=>n.id!==i)}async function j(i){const n=await b.complete(i),c=t.value.findIndex(S=>S.id===i);return c!==-1&&(t.value[c]=n.data),n.data}async function V(i,n){return(await b.createBlock(i,n)).data}async function e(i,n){return(await b.updateBlock(i,n)).data}async function l(i){await b.deleteBlock(i)}return{tasks:t,loading:d,error:o,fetchForDate:m,fetchAll:f,create:p,update:a,remove:u,complete:j,createBlock:V,updateBlock:e,deleteBlock:l}}),H=["id","value","placeholder","disabled","rows"],G=D({__name:"Textarea",props:{modelValue:{},placeholder:{},disabled:{type:Boolean},rows:{},class:{},id:{}},emits:["update:modelValue"],setup(t,{emit:d}){const o=t,m=d;return(f,p)=>(k(),g("textarea",{id:t.id,value:t.modelValue,placeholder:t.placeholder,disabled:t.disabled,rows:t.rows??3,class:N(w(A)("flex w-full rounded-md border border-input bg-background px-3 py-2 text-sm","ring-offset-background placeholder:text-muted-foreground","focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2","disabled:cursor-not-allowed disabled:opacity-50 resize-none",o.class)),onInput:p[0]||(p[0]=a=>m("update:modelValue",a.target.value))},null,42,H))}}),J=["id","value","disabled"],K=["selected"],B=D({__name:"Select",props:{modelValue:{},disabled:{type:Boolean},class:{},id:{},placeholder:{}},emits:["update:modelValue","change"],setup(t,{emit:d}){const o=t,m=d;return(f,p)=>(k(),g("select",{id:t.id,value:t.modelValue,disabled:t.disabled,class:N(w(A)("flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm","ring-offset-background focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2","disabled:cursor-not-allowed disabled:opacity-50",o.class)),onChange:p[0]||(p[0]=a=>m("update:modelValue",a.target.value))},[t.placeholder?(k(),g("option",{key:0,value:"",disabled:"",selected:!t.modelValue},x(t.placeholder),9,K)):C("",!0),P(f.$slots,"default")],42,J))}}),Q={list:()=>v.get("/api/projects")},R=I("projects",()=>{const t=_([]),d=_(!1);async function o(){if(!(t.value.length>0)){d.value=!0;try{const m=await Q.list();t.value=m.data}catch{t.value=[]}finally{d.value=!1}}}return{projects:t,loading:d,fetchProjects:o}}),X={class:"space-y-1.5"},Y={class:"space-y-1.5"},Z={class:"grid grid-cols-2 gap-3"},ee={class:"space-y-1.5"},te={class:"space-y-1.5"},ae={class:"grid grid-cols-2 gap-3"},le={class:"space-y-1.5"},se={class:"space-y-1.5"},oe={class:"grid grid-cols-2 gap-3"},de={class:"space-y-1.5"},ie={class:"space-y-1.5"},ne={key:0,class:"space-y-1.5"},ue=["value"],re={key:1,class:"space-y-1.5"},me=["value"],ye=D({__name:"TaskForm",props:{open:{type:Boolean},task:{default:null},defaultDate:{}},emits:["close","save"],setup(t,{emit:d}){const o=t,m=d,f=q(),p=R();E(()=>{p.fetchProjects()});const a=_({title:"",notes:"",planned_date:"",start_time:"",end_time:"",estimate_hours:1,status:"todo",priority:3,project_id:void 0,azure_work_item_id:void 0});L(()=>o.open,V=>{V&&(o.task?a.value={title:o.task.title,notes:o.task.notes??"",planned_date:o.task.planned_date??"",start_time:"",end_time:"",estimate_hours:o.task.estimate_hours??1,status:o.task.status,priority:o.task.priority,project_id:o.task.project_id??void 0,azure_work_item_id:o.task.azure_work_item_id??void 0}:a.value={title:"",notes:"",planned_date:o.defaultDate??"",start_time:"",end_time:"",estimate_hours:1,status:"todo",priority:3,project_id:void 0,azure_work_item_id:void 0},f.integration&&!f.workItems.length&&f.fetchWorkItems("open"))},{immediate:!0});const u=_(!1);async function j(){if(a.value.title.trim()){u.value=!0;try{const V={title:a.value.title,notes:a.value.notes||void 0,planned_date:a.value.planned_date,estimate_hours:a.value.estimate_hours,status:a.value.status,priority:a.value.priority,project_id:a.value.project_id||null,azure_work_item_id:a.value.azure_work_item_id||null};let e;a.value.planned_date&&a.value.start_time&&a.value.end_time&&(e={start_at:new Date(`${a.value.planned_date}T${a.value.start_time}:00`).toISOString(),end_at:new Date(`${a.value.planned_date}T${a.value.end_time}:00`).toISOString()}),m("save",V,e)}finally{u.value=!1}}}return(V,e)=>(k(),M(W,{open:t.open,title:t.task?"Edit Task":"New Task","max-width":"max-w-md",onClose:e[11]||(e[11]=l=>m("close"))},{footer:y(()=>[r(U,{variant:"outline",disabled:u.value,onClick:e[10]||(e[10]=l=>m("close"))},{default:y(()=>[...e[25]||(e[25]=[h("Cancel",-1)])]),_:1},8,["disabled"]),r(U,{loading:u.value,onClick:j},{default:y(()=>[h(x(t.task?"Update":"Create"),1)]),_:1},8,["loading"])]),default:y(()=>[s("form",{class:"space-y-4",onSubmit:O(j,["prevent"])},[s("div",X,[e[12]||(e[12]=s("label",{class:"text-sm font-medium text-foreground"},"Title *",-1)),r($,{modelValue:a.value.title,"onUpdate:modelValue":e[0]||(e[0]=l=>a.value.title=l),placeholder:"Task title...",disabled:u.value},null,8,["modelValue","disabled"])]),s("div",Y,[e[13]||(e[13]=s("label",{class:"text-sm font-medium text-foreground"},"Notes",-1)),r(G,{modelValue:a.value.notes,"onUpdate:modelValue":e[1]||(e[1]=l=>a.value.notes=l),placeholder:"Additional notes...",disabled:u.value},null,8,["modelValue","disabled"])]),s("div",Z,[s("div",ee,[e[14]||(e[14]=s("label",{class:"text-sm font-medium text-foreground"},"Planned Date",-1)),r($,{modelValue:a.value.planned_date,"onUpdate:modelValue":e[2]||(e[2]=l=>a.value.planned_date=l),type:"date",disabled:u.value},null,8,["modelValue","disabled"])]),s("div",te,[e[15]||(e[15]=s("label",{class:"text-sm font-medium text-foreground"},"Estimate (h)",-1)),r($,{modelValue:a.value.estimate_hours,"onUpdate:modelValue":e[3]||(e[3]=l=>a.value.estimate_hours=l),type:"number",min:"0.25",max:"24",step:"0.25",disabled:u.value},null,8,["modelValue","disabled"])])]),s("div",ae,[s("div",le,[e[16]||(e[16]=s("label",{class:"text-sm font-medium text-foreground"},[h("Start time "),s("span",{class:"text-muted-foreground font-normal"},"(optional)")],-1)),r($,{modelValue:a.value.start_time,"onUpdate:modelValue":e[4]||(e[4]=l=>a.value.start_time=l),type:"time",disabled:u.value},null,8,["modelValue","disabled"])]),s("div",se,[e[17]||(e[17]=s("label",{class:"text-sm font-medium text-foreground"},"End time",-1)),r($,{modelValue:a.value.end_time,"onUpdate:modelValue":e[5]||(e[5]=l=>a.value.end_time=l),type:"time",disabled:u.value},null,8,["modelValue","disabled"])])]),s("div",oe,[s("div",de,[e[19]||(e[19]=s("label",{class:"text-sm font-medium text-foreground"},"Status",-1)),r(B,{modelValue:a.value.status,"onUpdate:modelValue":e[6]||(e[6]=l=>a.value.status=l),disabled:u.value},{default:y(()=>[...e[18]||(e[18]=[s("option",{value:"todo"},"Todo",-1),s("option",{value:"doing"},"Doing",-1),s("option",{value:"done"},"Done",-1),s("option",{value:"cancelled"},"Cancelled",-1)])]),_:1},8,["modelValue","disabled"])]),s("div",ie,[e[21]||(e[21]=s("label",{class:"text-sm font-medium text-foreground"},"Priority",-1)),r(B,{modelValue:a.value.priority,"onUpdate:modelValue":e[7]||(e[7]=l=>a.value.priority=l),disabled:u.value},{default:y(()=>[...e[20]||(e[20]=[s("option",{value:"1"},"1 - Low",-1),s("option",{value:"2"},"2 - Normal",-1),s("option",{value:"3"},"3 - Medium",-1),s("option",{value:"4"},"4 - High",-1),s("option",{value:"5"},"5 - Critical",-1)])]),_:1},8,["modelValue","disabled"])])]),w(p).projects.length?(k(),g("div",ne,[e[23]||(e[23]=s("label",{class:"text-sm font-medium text-foreground"},"Project",-1)),r(B,{modelValue:a.value.project_id,"onUpdate:modelValue":e[8]||(e[8]=l=>a.value.project_id=l),disabled:u.value,placeholder:"Select project..."},{default:y(()=>[e[22]||(e[22]=s("option",{value:""},"None",-1)),(k(!0),g(z,null,T(w(p).projects,l=>(k(),g("option",{key:l.id,value:l.id},x(l.display_name)+x(l.job_number?` (${l.job_number})`:""),9,ue))),128))]),_:1},8,["modelValue","disabled"])])):C("",!0),w(f).workItems.length?(k(),g("div",re,[e[24]||(e[24]=s("label",{class:"text-sm font-medium text-foreground"},"Azure DevOps Work Item",-1)),r(B,{modelValue:a.value.azure_work_item_id,"onUpdate:modelValue":e[9]||(e[9]=l=>a.value.azure_work_item_id=l),disabled:u.value,placeholder:"Link work item..."},{default:y(()=>[(k(!0),g(z,null,T(w(f).workItems,l=>(k(),g("option",{key:l.id,value:l.id}," #"+x(l.ado_id)+" – "+x(l.title),9,me))),128))]),_:1},8,["modelValue","disabled"])])):C("",!0)],32)]),_:1},8,["open","title"]))}});export{ye as _,ge as u}; diff --git a/src/static/assets/admin-BRKJZipt.js b/src/static/assets/admin-DOjSzxjn.js similarity index 68% rename from src/static/assets/admin-BRKJZipt.js rename to src/static/assets/admin-DOjSzxjn.js index 1875ff3..beecdb2 100644 --- a/src/static/assets/admin-BRKJZipt.js +++ b/src/static/assets/admin-DOjSzxjn.js @@ -1 +1 @@ -import{D as e}from"./index-yrXqsixb.js";const i={users:()=>e.get("/api/admin/users"),keys:()=>e.get("/api/keys"),createKey:s=>e.post("/api/keys",s),revokeKey:s=>e.delete(`/api/keys/${s}`)};export{i as a}; +import{D as e}from"./index-DzSm5_bv.js";const i={users:()=>e.get("/api/admin/users"),keys:()=>e.get("/api/keys"),createKey:s=>e.post("/api/keys",s),revokeKey:s=>e.delete(`/api/keys/${s}`)};export{i as a}; diff --git a/src/static/assets/dashboard-Bay5szWb.js b/src/static/assets/dashboard-uOtmhTNc.js similarity index 88% rename from src/static/assets/dashboard-Bay5szWb.js rename to src/static/assets/dashboard-uOtmhTNc.js index 088e8df..d022b81 100644 --- a/src/static/assets/dashboard-Bay5szWb.js +++ b/src/static/assets/dashboard-uOtmhTNc.js @@ -1 +1 @@ -import{D as t}from"./index-yrXqsixb.js";const e={summary:a=>t.get("/api/dashboard/summary",{params:a}),projects:a=>t.get("/api/dashboard/projects",{params:a}),timeline:a=>t.get("/api/dashboard/timeline",{params:a}),monthly:a=>t.get("/api/dashboard/monthly",{params:a}),dow:a=>t.get("/api/dashboard/dow",{params:a}),tools:a=>t.get("/api/dashboard/tools",{params:a}),activity:a=>t.get("/api/dashboard/activity",{params:a}),calendar:a=>t.get("/api/dashboard/calendar",{params:a}),project:(a,o)=>t.get("/api/dashboard/project/"+a,{params:o})};export{e as d}; +import{D as t}from"./index-DzSm5_bv.js";const e={summary:a=>t.get("/api/dashboard/summary",{params:a}),projects:a=>t.get("/api/dashboard/projects",{params:a}),timeline:a=>t.get("/api/dashboard/timeline",{params:a}),monthly:a=>t.get("/api/dashboard/monthly",{params:a}),dow:a=>t.get("/api/dashboard/dow",{params:a}),tools:a=>t.get("/api/dashboard/tools",{params:a}),activity:a=>t.get("/api/dashboard/activity",{params:a}),calendar:a=>t.get("/api/dashboard/calendar",{params:a}),project:(a,o)=>t.get("/api/dashboard/project/"+a,{params:o})};export{e as d}; diff --git a/src/static/assets/devops-C_7zqRan.js b/src/static/assets/devops-S5lsRUq3.js similarity index 61% rename from src/static/assets/devops-C_7zqRan.js rename to src/static/assets/devops-S5lsRUq3.js index 5578bd8..78ded90 100644 --- a/src/static/assets/devops-C_7zqRan.js +++ b/src/static/assets/devops-S5lsRUq3.js @@ -1 +1 @@ -import{D as s,B as I,r as o}from"./index-yrXqsixb.js";const i={getIntegration:()=>s.get("/api/devops/integration"),saveIntegration:e=>s.put("/api/devops/integration",e),deleteIntegration:()=>s.delete("/api/devops/integration"),sync:()=>s.post("/api/devops/sync"),workItems:e=>s.get("/api/devops/work-items",{params:e?{state:e}:void 0})},m=I("devops",()=>{const e=o(null),r=o([]),l=o(!1),n=o(!1),c=o(null);async function u(){n.value=!0;try{const t=await i.getIntegration();e.value=t.data}catch{e.value=null}finally{n.value=!1}}async function d(t){const a=await i.saveIntegration(t);e.value=a.data}async function g(){await i.deleteIntegration(),e.value=null}async function f(){var t,a;l.value=!0,c.value=null;try{await i.sync(),await u()}catch(v){const p=v;throw c.value=((a=(t=p.response)==null?void 0:t.data)==null?void 0:a.detail)??p.message??"Sync failed",v}finally{l.value=!1}}async function y(t){n.value=!0;try{const a=await i.workItems(t);r.value=a.data}catch{r.value=[]}finally{n.value=!1}}return{integration:e,workItems:r,syncing:l,loading:n,error:c,fetchIntegration:u,saveIntegration:d,deleteIntegration:g,sync:f,fetchWorkItems:y}});export{m as u}; +import{D as s,A as I,q as o}from"./index-DzSm5_bv.js";const i={getIntegration:()=>s.get("/api/devops/integration"),saveIntegration:e=>s.put("/api/devops/integration",e),deleteIntegration:()=>s.delete("/api/devops/integration"),sync:()=>s.post("/api/devops/sync"),workItems:e=>s.get("/api/devops/work-items",{params:e?{state:e}:void 0})},m=I("devops",()=>{const e=o(null),l=o([]),r=o(!1),n=o(!1),c=o(null);async function u(){n.value=!0;try{const t=await i.getIntegration();e.value=t.data}catch{e.value=null}finally{n.value=!1}}async function d(t){const a=await i.saveIntegration(t);e.value=a.data}async function g(){await i.deleteIntegration(),e.value=null}async function f(){var t,a;r.value=!0,c.value=null;try{await i.sync(),await u()}catch(v){const p=v;throw c.value=((a=(t=p.response)==null?void 0:t.data)==null?void 0:a.detail)??p.message??"Sync failed",v}finally{r.value=!1}}async function y(t){n.value=!0;try{const a=await i.workItems(t);l.value=a.data}catch{l.value=[]}finally{n.value=!1}}return{integration:e,workItems:l,syncing:r,loading:n,error:c,fetchIntegration:u,saveIntegration:d,deleteIntegration:g,sync:f,fetchWorkItems:y}});export{m as u}; diff --git a/src/static/assets/index-BXlrCgg3.css b/src/static/assets/index-C-CL-7fz.css similarity index 57% rename from src/static/assets/index-BXlrCgg3.css rename to src/static/assets/index-C-CL-7fz.css index 84eab04..c3d1f61 100644 --- a/src/static/assets/index-BXlrCgg3.css +++ b/src/static/assets/index-C-CL-7fz.css @@ -1 +1 @@ -@import"https://api.fontshare.com/v2/css?f[]=satoshi@700,500,400&display=swap";@import"https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap";.slide-up-enter-active[data-v-5b6580b3],.slide-up-leave-active[data-v-5b6580b3]{transition:all .25s cubic-bezier(.34,1.56,.64,1)}.slide-up-enter-from[data-v-5b6580b3],.slide-up-leave-to[data-v-5b6580b3]{opacity:0;transform:translateY(20px) scale(.95)}.prose[data-v-5b6580b3] li{margin:.125rem 0}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--background: 0 0% 98%;--foreground: 222 47% 11%;--card: 0 0% 100%;--card-foreground: 222 47% 11%;--popover: 0 0% 100%;--popover-foreground: 222 47% 11%;--primary: 191 91% 37%;--primary-foreground: 0 0% 100%;--secondary: 210 40% 94%;--secondary-foreground: 222 47% 11%;--muted: 210 40% 94%;--muted-foreground: 215 16% 47%;--accent: 191 91% 92%;--accent-foreground: 191 91% 25%;--destructive: 0 84% 60%;--destructive-foreground: 0 0% 100%;--border: 214 32% 88%;--input: 214 32% 88%;--ring: 191 91% 37%;--radius: .5rem;--sidebar-background: 210 40% 96%;--sidebar-foreground: 222 47% 11%;--sidebar-primary: 191 91% 37%;--sidebar-primary-foreground: 0 0% 100%;--sidebar-accent: 191 91% 92%;--sidebar-accent-foreground: 191 91% 25%;--sidebar-border: 214 32% 88%;--sidebar-ring: 191 91% 37%;--success: 158 64% 40%;--warning: 38 92% 50%}.dark{--background: 226 49% 8%;--foreground: 220 40% 92%;--card: 220 44% 10%;--card-foreground: 220 40% 92%;--popover: 220 44% 12%;--popover-foreground: 220 40% 92%;--primary: 200 100% 67%;--primary-foreground: 226 49% 8%;--secondary: 220 30% 14%;--secondary-foreground: 220 20% 75%;--muted: 220 30% 12%;--muted-foreground: 220 12% 52%;--accent: 220 30% 14%;--accent-foreground: 220 40% 92%;--destructive: 0 72% 51%;--destructive-foreground: 220 40% 98%;--border: 220 28% 17%;--input: 220 28% 17%;--ring: 200 100% 67%;--success: 158 64% 52%;--warning: 38 92% 60%}*{border-color:hsl(var(--border))}body{background-color:hsl(var(--background));color:hsl(var(--foreground));font-family:Satoshi,Inter,system-ui,-apple-system,sans-serif;font-feature-settings:"rlig" 1,"calt" 1;-webkit-font-smoothing:antialiased}.tabular-nums,[data-value],.kpi-value{font-family:JetBrains Mono,Fira Code,ui-monospace,monospace;font-variant-numeric:tabular-nums}::-webkit-scrollbar{width:4px;height:4px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:#252e41;border-radius:9999px}::-webkit-scrollbar-thumb:hover{background:#374562}.container{width:100%}@media (min-width: 640px){.container{max-width:640px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-width: 1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.inset-y-0{top:0;bottom:0}.-right-1{right:-.25rem}.-right-4{right:-1rem}.-top-1{top:-.25rem}.-top-4{top:-1rem}.bottom-0{bottom:0}.bottom-6{bottom:1.5rem}.left-0{left:0}.right-0{right:0}.right-2{right:.5rem}.right-6{right:1.5rem}.top-0{top:0}.top-1\/2{top:50%}.z-0{z-index:0}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-top:.25rem;margin-bottom:.25rem}.mb-0\.5{margin-bottom:.125rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-2{margin-left:.5rem}.ml-4{margin-left:1rem}.ml-auto{margin-left:auto}.mr-1\.5{margin-right:.375rem}.mr-2{margin-right:.5rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-auto{margin-top:auto}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.\!block{display:block!important}.block{display:block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-0\.5{height:.125rem}.h-1\.5{height:.375rem}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-2{height:.5rem}.h-20{height:5rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-32{height:8rem}.h-4{height:1rem}.h-40{height:10rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-24{max-height:6rem}.max-h-\[600px\]{max-height:600px}.min-h-0{min-height:0px}.min-h-screen{min-height:100vh}.w-0\.5{width:.125rem}.w-1\.5{width:.375rem}.w-10{width:2.5rem}.w-11{width:2.75rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-2{width:.5rem}.w-20{width:5rem}.w-24{width:6rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-32{width:8rem}.w-36{width:9rem}.w-4{width:1rem}.w-40{width:10rem}.w-5{width:1.25rem}.w-56{width:14rem}.w-6{width:1.5rem}.w-60{width:15rem}.w-7{width:1.75rem}.w-72{width:18rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-\[380px\]{width:380px}.w-full{width:100%}.w-px{width:1px}.min-w-0{min-width:0px}.max-w-2xl{max-width:42rem}.max-w-\[100px\]{max-width:100px}.max-w-\[120px\]{max-width:120px}.max-w-\[160px\]{max-width:160px}.max-w-\[200px\]{max-width:200px}.max-w-\[80\%\]{max-width:80%}.max-w-\[90\%\]{max-width:90%}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-none{max-width:none}.max-w-sm{max-width:24rem}.flex-1{flex:1 1 0%}.flex-shrink-0,.shrink-0{flex-shrink:0}.-translate-x-full{--tw-translate-x: -100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes bounce{0%,to{transform:translateY(-25%);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{transform:none;animation-timing-function:cubic-bezier(0,0,.2,1)}}.animate-bounce{animation:bounce 1s infinite}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-grab{cursor:grab}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.cursor-s-resize{cursor:s-resize}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.resize{resize:both}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-px{gap:1px}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-2\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.625rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.625rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-xl{border-radius:.75rem}.rounded-r-full{border-top-right-radius:9999px;border-bottom-right-radius:9999px}.rounded-t{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.rounded-tl-sm{border-top-left-radius:calc(var(--radius) - 4px)}.rounded-tr-sm{border-top-right-radius:calc(var(--radius) - 4px)}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-amber-500\/30{border-color:#f59e0b4d}.border-border{border-color:hsl(var(--border))}.border-border\/20{border-color:hsl(var(--border) / .2)}.border-border\/30{border-color:hsl(var(--border) / .3)}.border-border\/40{border-color:hsl(var(--border) / .4)}.border-border\/60{border-color:hsl(var(--border) / .6)}.border-destructive\/30{border-color:hsl(var(--destructive) / .3)}.border-emerald-500\/30{border-color:#10b9814d}.border-gray-600{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity, 1))}.border-gray-700{--tw-border-opacity: 1;border-color:rgb(55 65 81 / var(--tw-border-opacity, 1))}.border-input{border-color:hsl(var(--input))}.border-primary\/20{border-color:hsl(var(--primary) / .2)}.bg-\[hsl\(220_44\%_8\%\)\]{--tw-bg-opacity: 1;background-color:hsl(220 44% 8% / var(--tw-bg-opacity, 1))}.bg-\[hsl\(var\(--success\)\)\]{background-color:hsl(var(--success))}.bg-amber-400{--tw-bg-opacity: 1;background-color:rgb(251 191 36 / var(--tw-bg-opacity, 1))}.bg-amber-400\/10{background-color:#fbbf241a}.bg-amber-500{--tw-bg-opacity: 1;background-color:rgb(245 158 11 / var(--tw-bg-opacity, 1))}.bg-amber-500\/10{background-color:#f59e0b1a}.bg-amber-500\/20{background-color:#f59e0b33}.bg-background{background-color:hsl(var(--background))}.bg-black\/60{background-color:#0009}.bg-blue-500\/10{background-color:#3b82f61a}.bg-border{background-color:hsl(var(--border))}.bg-card{background-color:hsl(var(--card))}.bg-card\/95{background-color:hsl(var(--card) / .95)}.bg-destructive{background-color:hsl(var(--destructive))}.bg-destructive\/10{background-color:hsl(var(--destructive) / .1)}.bg-destructive\/90{background-color:hsl(var(--destructive) / .9)}.bg-emerald-500{--tw-bg-opacity: 1;background-color:rgb(16 185 129 / var(--tw-bg-opacity, 1))}.bg-emerald-500\/10{background-color:#10b9811a}.bg-emerald-500\/20{background-color:#10b98133}.bg-gray-500{--tw-bg-opacity: 1;background-color:rgb(107 114 128 / var(--tw-bg-opacity, 1))}.bg-gray-700{--tw-bg-opacity: 1;background-color:rgb(55 65 81 / var(--tw-bg-opacity, 1))}.bg-gray-800{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}.bg-gray-900{--tw-bg-opacity: 1;background-color:rgb(17 24 39 / var(--tw-bg-opacity, 1))}.bg-green-500\/10{background-color:#22c55e1a}.bg-muted{background-color:hsl(var(--muted))}.bg-muted-foreground{background-color:hsl(var(--muted-foreground))}.bg-muted\/30{background-color:hsl(var(--muted) / .3)}.bg-primary{background-color:hsl(var(--primary))}.bg-primary\/10{background-color:hsl(var(--primary) / .1)}.bg-primary\/15{background-color:hsl(var(--primary) / .15)}.bg-primary\/20{background-color:hsl(var(--primary) / .2)}.bg-primary\/5{background-color:hsl(var(--primary) / .05)}.bg-primary\/70{background-color:hsl(var(--primary) / .7)}.bg-primary\/90{background-color:hsl(var(--primary) / .9)}.bg-red-500{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity, 1))}.bg-red-900\/40{background-color:#7f1d1d66}.bg-secondary{background-color:hsl(var(--secondary))}.bg-secondary\/80{background-color:hsl(var(--secondary) / .8)}.bg-white\/60{background-color:#fff9}.object-cover{-o-object-fit:cover;object-fit:cover}.p-0{padding:0}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0{padding-top:0;padding-bottom:0}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-2{padding-bottom:.5rem}.pb-4{padding-bottom:1rem}.pb-6{padding-bottom:1.5rem}.pt-0{padding-top:0}.pt-4{padding-top:1rem}.pt-6{padding-top:1.5rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-\[10px\]{font-size:10px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.tabular-nums{--tw-numeric-spacing: tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-none{line-height:1}.leading-tight{line-height:1.25}.tracking-\[0\.1em\]{letter-spacing:.1em}.tracking-tight{letter-spacing:-.025em}.tracking-wide{letter-spacing:.025em}.tracking-widest{letter-spacing:.1em}.text-\[hsl\(var\(--success\)\)\]{color:hsl(var(--success))}.text-accent-foreground{color:hsl(var(--accent-foreground))}.text-amber-400{--tw-text-opacity: 1;color:rgb(251 191 36 / var(--tw-text-opacity, 1))}.text-blue-400{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.text-card-foreground{color:hsl(var(--card-foreground))}.text-current{color:currentColor}.text-destructive{color:hsl(var(--destructive))}.text-destructive-foreground{color:hsl(var(--destructive-foreground))}.text-emerald-400{--tw-text-opacity: 1;color:rgb(52 211 153 / var(--tw-text-opacity, 1))}.text-foreground{color:hsl(var(--foreground))}.text-gray-200{--tw-text-opacity: 1;color:rgb(229 231 235 / var(--tw-text-opacity, 1))}.text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.text-gray-900{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}.text-green-400{--tw-text-opacity: 1;color:rgb(74 222 128 / var(--tw-text-opacity, 1))}.text-muted-foreground{color:hsl(var(--muted-foreground))}.text-muted-foreground\/30{color:hsl(var(--muted-foreground) / .3)}.text-muted-foreground\/60{color:hsl(var(--muted-foreground) / .6)}.text-primary{color:hsl(var(--primary))}.text-primary-foreground{color:hsl(var(--primary-foreground))}.text-primary\/80{color:hsl(var(--primary) / .8)}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.text-secondary-foreground{color:hsl(var(--secondary-foreground))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.underline-offset-4{text-underline-offset:4px}.placeholder-gray-500::-moz-placeholder{--tw-placeholder-opacity: 1;color:rgb(107 114 128 / var(--tw-placeholder-opacity, 1))}.placeholder-gray-500::placeholder{--tw-placeholder-opacity: 1;color:rgb(107 114 128 / var(--tw-placeholder-opacity, 1))}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-25{opacity:.25}.opacity-50{opacity:.5}.opacity-75{opacity:.75}.opacity-80{opacity:.8}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline{outline-style:solid}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-border{--tw-ring-color: hsl(var(--border))}.ring-primary\/15{--tw-ring-color: hsl(var(--primary) / .15)}.ring-primary\/20{--tw-ring-color: hsl(var(--primary) / .2)}.ring-primary\/25{--tw-ring-color: hsl(var(--primary) / .25)}.ring-offset-background{--tw-ring-offset-color: hsl(var(--background))}.blur{--tw-blur: blur(8px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-sm{--tw-backdrop-blur: blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-150{transition-duration:.15s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.panel-glow{box-shadow:0 0 0 1px hsl(var(--border)),0 4px 24px -4px #05080f99}.panel-glow-hover:hover{box-shadow:0 0 0 1px #57c7ff2e,0 8px 32px -4px #57c7ff14}.file\:border-0::file-selector-button{border-width:0px}.file\:bg-transparent::file-selector-button{background-color:transparent}.file\:text-sm::file-selector-button{font-size:.875rem;line-height:1.25rem}.file\:font-medium::file-selector-button{font-weight:500}.placeholder\:text-muted-foreground::-moz-placeholder{color:hsl(var(--muted-foreground))}.placeholder\:text-muted-foreground::placeholder{color:hsl(var(--muted-foreground))}.last\:border-0:last-child{border-width:0px}.hover\:scale-105:hover{--tw-scale-x: 1.05;--tw-scale-y: 1.05;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:border-amber-400:hover{--tw-border-opacity: 1;border-color:rgb(251 191 36 / var(--tw-border-opacity, 1))}.hover\:border-primary\/50:hover{border-color:hsl(var(--primary) / .5)}.hover\:bg-accent:hover{background-color:hsl(var(--accent))}.hover\:bg-amber-300:hover{--tw-bg-opacity: 1;background-color:rgb(252 211 77 / var(--tw-bg-opacity, 1))}.hover\:bg-destructive\/90:hover{background-color:hsl(var(--destructive) / .9)}.hover\:bg-emerald-500\/20:hover{background-color:#10b98133}.hover\:bg-muted:hover{background-color:hsl(var(--muted))}.hover\:bg-muted\/30:hover{background-color:hsl(var(--muted) / .3)}.hover\:bg-muted\/50:hover{background-color:hsl(var(--muted) / .5)}.hover\:bg-primary:hover{background-color:hsl(var(--primary))}.hover\:bg-primary\/90:hover{background-color:hsl(var(--primary) / .9)}.hover\:bg-red-500\/20:hover{background-color:#ef444433}.hover\:bg-red-900\/60:hover{background-color:#7f1d1d99}.hover\:bg-secondary\/80:hover{background-color:hsl(var(--secondary) / .8)}.hover\:text-accent-foreground:hover{color:hsl(var(--accent-foreground))}.hover\:text-amber-400:hover{--tw-text-opacity: 1;color:rgb(251 191 36 / var(--tw-text-opacity, 1))}.hover\:text-foreground:hover{color:hsl(var(--foreground))}.hover\:text-primary:hover{color:hsl(var(--primary))}.hover\:text-white:hover{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.hover\:underline:hover{text-decoration-line:underline}.focus\:border-amber-400:focus{--tw-border-opacity: 1;border-color:rgb(251 191 36 / var(--tw-border-opacity, 1))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-1:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-ring:focus{--tw-ring-color: hsl(var(--ring))}.focus\:ring-offset-2:focus{--tw-ring-offset-width: 2px}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-ring:focus-visible{--tw-ring-color: hsl(var(--ring))}.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width: 2px}.active\:scale-95:active{--tw-scale-x: .95;--tw-scale-y: .95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.active\:cursor-grabbing:active{cursor:grabbing}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.group:hover .group-hover\:text-muted-foreground{color:hsl(var(--muted-foreground))}.group:hover .group-hover\:opacity-100{opacity:1}.dark\:block:is(.dark *){display:block}.dark\:hidden:is(.dark *){display:none}@media (min-width: 640px){.sm\:block{display:block}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width: 768px){.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (min-width: 1024px){.lg\:relative{position:relative}.lg\:hidden{display:none}.lg\:translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (min-width: 1280px){.xl\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.xl\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}} +@import"https://api.fontshare.com/v2/css?f[]=satoshi@700,500,400&display=swap";@import"https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap";.slide-up-enter-active[data-v-5b6580b3],.slide-up-leave-active[data-v-5b6580b3]{transition:all .25s cubic-bezier(.34,1.56,.64,1)}.slide-up-enter-from[data-v-5b6580b3],.slide-up-leave-to[data-v-5b6580b3]{opacity:0;transform:translateY(20px) scale(.95)}.prose[data-v-5b6580b3] li{margin:.125rem 0}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--background: 0 0% 98%;--foreground: 222 47% 11%;--card: 0 0% 100%;--card-foreground: 222 47% 11%;--popover: 0 0% 100%;--popover-foreground: 222 47% 11%;--primary: 191 91% 37%;--primary-foreground: 0 0% 100%;--secondary: 210 40% 94%;--secondary-foreground: 222 47% 11%;--muted: 210 40% 94%;--muted-foreground: 215 16% 47%;--accent: 191 91% 92%;--accent-foreground: 191 91% 25%;--destructive: 0 84% 60%;--destructive-foreground: 0 0% 100%;--border: 214 32% 88%;--input: 214 32% 88%;--ring: 191 91% 37%;--radius: .5rem;--sidebar-background: 210 40% 96%;--sidebar-foreground: 222 47% 11%;--sidebar-primary: 191 91% 37%;--sidebar-primary-foreground: 0 0% 100%;--sidebar-accent: 191 91% 92%;--sidebar-accent-foreground: 191 91% 25%;--sidebar-border: 214 32% 88%;--sidebar-ring: 191 91% 37%;--success: 158 64% 40%;--warning: 38 92% 50%}.dark{--background: 226 49% 8%;--foreground: 220 40% 92%;--card: 220 44% 10%;--card-foreground: 220 40% 92%;--popover: 220 44% 12%;--popover-foreground: 220 40% 92%;--primary: 200 100% 67%;--primary-foreground: 226 49% 8%;--secondary: 220 30% 14%;--secondary-foreground: 220 20% 75%;--muted: 220 30% 12%;--muted-foreground: 220 12% 52%;--accent: 220 30% 14%;--accent-foreground: 220 40% 92%;--destructive: 0 72% 51%;--destructive-foreground: 220 40% 98%;--border: 220 28% 17%;--input: 220 28% 17%;--ring: 200 100% 67%;--success: 158 64% 52%;--warning: 38 92% 60%}*{border-color:hsl(var(--border))}body{background-color:hsl(var(--background));color:hsl(var(--foreground));font-family:Satoshi,Inter,system-ui,-apple-system,sans-serif;font-feature-settings:"rlig" 1,"calt" 1;-webkit-font-smoothing:antialiased}.tabular-nums,[data-value],.kpi-value{font-family:JetBrains Mono,Fira Code,ui-monospace,monospace;font-variant-numeric:tabular-nums}::-webkit-scrollbar{width:4px;height:4px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:#252e41;border-radius:9999px}::-webkit-scrollbar-thumb:hover{background:#374562}.container{width:100%}@media (min-width: 640px){.container{max-width:640px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-width: 1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.inset-y-0{top:0;bottom:0}.-right-1{right:-.25rem}.-right-4{right:-1rem}.-top-1{top:-.25rem}.-top-4{top:-1rem}.bottom-0{bottom:0}.bottom-6{bottom:1.5rem}.left-0{left:0}.right-0{right:0}.right-2{right:.5rem}.right-6{right:1.5rem}.top-0{top:0}.top-1\/2{top:50%}.z-0{z-index:0}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-top:.25rem;margin-bottom:.25rem}.mb-0\.5{margin-bottom:.125rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-2{margin-left:.5rem}.ml-4{margin-left:1rem}.ml-auto{margin-left:auto}.mr-1\.5{margin-right:.375rem}.mr-2{margin-right:.5rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-auto{margin-top:auto}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.\!block{display:block!important}.block{display:block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-0\.5{height:.125rem}.h-1\.5{height:.375rem}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-2{height:.5rem}.h-20{height:5rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-32{height:8rem}.h-4{height:1rem}.h-40{height:10rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-24{max-height:6rem}.max-h-\[600px\]{max-height:600px}.min-h-0{min-height:0px}.min-h-screen{min-height:100vh}.w-0\.5{width:.125rem}.w-1\.5{width:.375rem}.w-10{width:2.5rem}.w-11{width:2.75rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-2{width:.5rem}.w-20{width:5rem}.w-24{width:6rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-32{width:8rem}.w-36{width:9rem}.w-4{width:1rem}.w-40{width:10rem}.w-5{width:1.25rem}.w-56{width:14rem}.w-6{width:1.5rem}.w-60{width:15rem}.w-7{width:1.75rem}.w-72{width:18rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-\[380px\]{width:380px}.w-full{width:100%}.w-px{width:1px}.min-w-0{min-width:0px}.max-w-2xl{max-width:42rem}.max-w-\[100px\]{max-width:100px}.max-w-\[120px\]{max-width:120px}.max-w-\[160px\]{max-width:160px}.max-w-\[200px\]{max-width:200px}.max-w-\[80\%\]{max-width:80%}.max-w-\[90\%\]{max-width:90%}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-none{max-width:none}.max-w-sm{max-width:24rem}.flex-1{flex:1 1 0%}.flex-shrink-0,.shrink-0{flex-shrink:0}.-translate-x-full{--tw-translate-x: -100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes bounce{0%,to{transform:translateY(-25%);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{transform:none;animation-timing-function:cubic-bezier(0,0,.2,1)}}.animate-bounce{animation:bounce 1s infinite}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-grab{cursor:grab}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.cursor-s-resize{cursor:s-resize}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.resize{resize:both}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-px{gap:1px}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-2\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.625rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.625rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-xl{border-radius:.75rem}.rounded-r-full{border-top-right-radius:9999px;border-bottom-right-radius:9999px}.rounded-t{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.rounded-tl-sm{border-top-left-radius:calc(var(--radius) - 4px)}.rounded-tr-sm{border-top-right-radius:calc(var(--radius) - 4px)}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-amber-500\/30{border-color:#f59e0b4d}.border-border{border-color:hsl(var(--border))}.border-border\/20{border-color:hsl(var(--border) / .2)}.border-border\/30{border-color:hsl(var(--border) / .3)}.border-border\/40{border-color:hsl(var(--border) / .4)}.border-border\/60{border-color:hsl(var(--border) / .6)}.border-destructive\/30{border-color:hsl(var(--destructive) / .3)}.border-emerald-500\/30{border-color:#10b9814d}.border-gray-600{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity, 1))}.border-gray-700{--tw-border-opacity: 1;border-color:rgb(55 65 81 / var(--tw-border-opacity, 1))}.border-input{border-color:hsl(var(--input))}.border-primary\/20{border-color:hsl(var(--primary) / .2)}.bg-\[hsl\(220_44\%_8\%\)\]{--tw-bg-opacity: 1;background-color:hsl(220 44% 8% / var(--tw-bg-opacity, 1))}.bg-\[hsl\(var\(--success\)\)\]{background-color:hsl(var(--success))}.bg-amber-400{--tw-bg-opacity: 1;background-color:rgb(251 191 36 / var(--tw-bg-opacity, 1))}.bg-amber-400\/10{background-color:#fbbf241a}.bg-amber-500{--tw-bg-opacity: 1;background-color:rgb(245 158 11 / var(--tw-bg-opacity, 1))}.bg-amber-500\/10{background-color:#f59e0b1a}.bg-amber-500\/20{background-color:#f59e0b33}.bg-background{background-color:hsl(var(--background))}.bg-black\/60{background-color:#0009}.bg-blue-500\/10{background-color:#3b82f61a}.bg-border{background-color:hsl(var(--border))}.bg-card{background-color:hsl(var(--card))}.bg-card\/95{background-color:hsl(var(--card) / .95)}.bg-destructive{background-color:hsl(var(--destructive))}.bg-destructive\/10{background-color:hsl(var(--destructive) / .1)}.bg-destructive\/90{background-color:hsl(var(--destructive) / .9)}.bg-emerald-500{--tw-bg-opacity: 1;background-color:rgb(16 185 129 / var(--tw-bg-opacity, 1))}.bg-emerald-500\/10{background-color:#10b9811a}.bg-emerald-500\/20{background-color:#10b98133}.bg-gray-500{--tw-bg-opacity: 1;background-color:rgb(107 114 128 / var(--tw-bg-opacity, 1))}.bg-gray-700{--tw-bg-opacity: 1;background-color:rgb(55 65 81 / var(--tw-bg-opacity, 1))}.bg-gray-800{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}.bg-gray-900{--tw-bg-opacity: 1;background-color:rgb(17 24 39 / var(--tw-bg-opacity, 1))}.bg-green-500\/10{background-color:#22c55e1a}.bg-muted{background-color:hsl(var(--muted))}.bg-muted-foreground{background-color:hsl(var(--muted-foreground))}.bg-muted\/30{background-color:hsl(var(--muted) / .3)}.bg-primary{background-color:hsl(var(--primary))}.bg-primary\/10{background-color:hsl(var(--primary) / .1)}.bg-primary\/15{background-color:hsl(var(--primary) / .15)}.bg-primary\/20{background-color:hsl(var(--primary) / .2)}.bg-primary\/5{background-color:hsl(var(--primary) / .05)}.bg-primary\/70{background-color:hsl(var(--primary) / .7)}.bg-primary\/90{background-color:hsl(var(--primary) / .9)}.bg-red-500{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity, 1))}.bg-red-900\/40{background-color:#7f1d1d66}.bg-secondary{background-color:hsl(var(--secondary))}.bg-secondary\/80{background-color:hsl(var(--secondary) / .8)}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-white\/60{background-color:#fff9}.object-cover{-o-object-fit:cover;object-fit:cover}.p-0{padding:0}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0{padding-top:0;padding-bottom:0}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-2{padding-bottom:.5rem}.pb-4{padding-bottom:1rem}.pb-6{padding-bottom:1.5rem}.pt-0{padding-top:0}.pt-4{padding-top:1rem}.pt-6{padding-top:1.5rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-\[10px\]{font-size:10px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.tabular-nums{--tw-numeric-spacing: tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-none{line-height:1}.leading-tight{line-height:1.25}.tracking-\[0\.1em\]{letter-spacing:.1em}.tracking-tight{letter-spacing:-.025em}.tracking-wide{letter-spacing:.025em}.tracking-widest{letter-spacing:.1em}.text-\[hsl\(var\(--success\)\)\]{color:hsl(var(--success))}.text-accent-foreground{color:hsl(var(--accent-foreground))}.text-amber-400{--tw-text-opacity: 1;color:rgb(251 191 36 / var(--tw-text-opacity, 1))}.text-blue-400{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.text-card-foreground{color:hsl(var(--card-foreground))}.text-current{color:currentColor}.text-destructive{color:hsl(var(--destructive))}.text-destructive-foreground{color:hsl(var(--destructive-foreground))}.text-emerald-400{--tw-text-opacity: 1;color:rgb(52 211 153 / var(--tw-text-opacity, 1))}.text-foreground{color:hsl(var(--foreground))}.text-gray-200{--tw-text-opacity: 1;color:rgb(229 231 235 / var(--tw-text-opacity, 1))}.text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.text-gray-900{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}.text-green-400{--tw-text-opacity: 1;color:rgb(74 222 128 / var(--tw-text-opacity, 1))}.text-muted-foreground{color:hsl(var(--muted-foreground))}.text-muted-foreground\/30{color:hsl(var(--muted-foreground) / .3)}.text-muted-foreground\/60{color:hsl(var(--muted-foreground) / .6)}.text-primary{color:hsl(var(--primary))}.text-primary-foreground{color:hsl(var(--primary-foreground))}.text-primary\/80{color:hsl(var(--primary) / .8)}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.text-secondary-foreground{color:hsl(var(--secondary-foreground))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.underline-offset-4{text-underline-offset:4px}.placeholder-gray-500::-moz-placeholder{--tw-placeholder-opacity: 1;color:rgb(107 114 128 / var(--tw-placeholder-opacity, 1))}.placeholder-gray-500::placeholder{--tw-placeholder-opacity: 1;color:rgb(107 114 128 / var(--tw-placeholder-opacity, 1))}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-25{opacity:.25}.opacity-50{opacity:.5}.opacity-75{opacity:.75}.opacity-80{opacity:.8}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline{outline-style:solid}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-border{--tw-ring-color: hsl(var(--border))}.ring-primary\/15{--tw-ring-color: hsl(var(--primary) / .15)}.ring-primary\/20{--tw-ring-color: hsl(var(--primary) / .2)}.ring-primary\/25{--tw-ring-color: hsl(var(--primary) / .25)}.ring-offset-background{--tw-ring-offset-color: hsl(var(--background))}.blur{--tw-blur: blur(8px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-sm{--tw-backdrop-blur: blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-150{transition-duration:.15s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.panel-glow{box-shadow:0 0 0 1px hsl(var(--border)),0 4px 24px -4px #05080f99}.panel-glow-hover:hover{box-shadow:0 0 0 1px #57c7ff2e,0 8px 32px -4px #57c7ff14}.file\:border-0::file-selector-button{border-width:0px}.file\:bg-transparent::file-selector-button{background-color:transparent}.file\:text-sm::file-selector-button{font-size:.875rem;line-height:1.25rem}.file\:font-medium::file-selector-button{font-weight:500}.placeholder\:text-muted-foreground::-moz-placeholder{color:hsl(var(--muted-foreground))}.placeholder\:text-muted-foreground::placeholder{color:hsl(var(--muted-foreground))}.last\:border-0:last-child{border-width:0px}.hover\:scale-105:hover{--tw-scale-x: 1.05;--tw-scale-y: 1.05;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:border-amber-400:hover{--tw-border-opacity: 1;border-color:rgb(251 191 36 / var(--tw-border-opacity, 1))}.hover\:border-primary\/50:hover{border-color:hsl(var(--primary) / .5)}.hover\:bg-accent:hover{background-color:hsl(var(--accent))}.hover\:bg-amber-300:hover{--tw-bg-opacity: 1;background-color:rgb(252 211 77 / var(--tw-bg-opacity, 1))}.hover\:bg-destructive\/90:hover{background-color:hsl(var(--destructive) / .9)}.hover\:bg-emerald-500\/20:hover{background-color:#10b98133}.hover\:bg-gray-50:hover{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}.hover\:bg-muted:hover{background-color:hsl(var(--muted))}.hover\:bg-muted\/30:hover{background-color:hsl(var(--muted) / .3)}.hover\:bg-muted\/50:hover{background-color:hsl(var(--muted) / .5)}.hover\:bg-primary:hover{background-color:hsl(var(--primary))}.hover\:bg-primary\/90:hover{background-color:hsl(var(--primary) / .9)}.hover\:bg-red-500\/20:hover{background-color:#ef444433}.hover\:bg-red-900\/60:hover{background-color:#7f1d1d99}.hover\:bg-secondary\/80:hover{background-color:hsl(var(--secondary) / .8)}.hover\:text-accent-foreground:hover{color:hsl(var(--accent-foreground))}.hover\:text-amber-400:hover{--tw-text-opacity: 1;color:rgb(251 191 36 / var(--tw-text-opacity, 1))}.hover\:text-foreground:hover{color:hsl(var(--foreground))}.hover\:text-primary:hover{color:hsl(var(--primary))}.hover\:text-white:hover{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.hover\:underline:hover{text-decoration-line:underline}.focus\:border-amber-400:focus{--tw-border-opacity: 1;border-color:rgb(251 191 36 / var(--tw-border-opacity, 1))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-1:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-primary:focus{--tw-ring-color: hsl(var(--primary))}.focus\:ring-ring:focus{--tw-ring-color: hsl(var(--ring))}.focus\:ring-offset-2:focus{--tw-ring-offset-width: 2px}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-ring:focus-visible{--tw-ring-color: hsl(var(--ring))}.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width: 2px}.active\:scale-95:active{--tw-scale-x: .95;--tw-scale-y: .95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.active\:cursor-grabbing:active{cursor:grabbing}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.group:hover .group-hover\:text-muted-foreground{color:hsl(var(--muted-foreground))}.group:hover .group-hover\:opacity-100{opacity:1}.dark\:block:is(.dark *){display:block}.dark\:hidden:is(.dark *){display:none}@media (min-width: 640px){.sm\:block{display:block}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width: 768px){.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (min-width: 1024px){.lg\:relative{position:relative}.lg\:hidden{display:none}.lg\:translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (min-width: 1280px){.xl\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.xl\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}} diff --git a/src/static/assets/index-DzSm5_bv.js b/src/static/assets/index-DzSm5_bv.js new file mode 100644 index 0000000..2d4b9e4 --- /dev/null +++ b/src/static/assets/index-DzSm5_bv.js @@ -0,0 +1,46 @@ +const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/LoginView-DzMVaLbC.js","assets/CardContent.vue_vue_type_script_setup_true_lang-B899D1fp.js","assets/utils-7WVCegLb.js","assets/DashboardView-Cvjfxfcs.js","assets/dashboard-uOtmhTNc.js","assets/CardTitle.vue_vue_type_script_setup_true_lang-ByUGRP-t.js","assets/Progress.vue_vue_type_script_setup_true_lang-DK67Z5Fm.js","assets/Button.vue_vue_type_script_setup_true_lang-D97aKlXO.js","assets/Spinner.vue_vue_type_script_setup_true_lang-DxuuceC3.js","assets/CalendarView-CVfEc5OT.js","assets/TaskForm.vue_vue_type_script_setup_true_lang-Dq5zJejp.js","assets/Dialog.vue_vue_type_script_setup_true_lang-Bpehdtti.js","assets/Input.vue_vue_type_script_setup_true_lang-DX_izdWK.js","assets/devops-S5lsRUq3.js","assets/Badge.vue_vue_type_script_setup_true_lang-CaB6FyQ0.js","assets/CalendarView-DRWiX2N8.css","assets/PlannerView-DJPGnDPz.js","assets/ProjectsView-VxSshwHq.js","assets/ProjectDetailView-2QTgygyj.js","assets/LiveView-Df9pKcnA.js","assets/ReportsView-Dgj4QJox.js","assets/ReportsView-BczQ2gJa.css","assets/KeysView-Buk66uDj.js","assets/admin-DOjSzxjn.js","assets/DevopsView-L2Z-AJUn.js","assets/SettingsView-DsEb6gx-.js","assets/AdminView-DUmZvUGQ.js"])))=>i.map(i=>d[i]); +var Jl=n=>{throw TypeError(n)};var da=(n,e,t)=>e.has(n)||Jl("Cannot "+t);var O=(n,e,t)=>(da(n,e,"read from private field"),t?t.call(n):e.get(n)),Ee=(n,e,t)=>e.has(n)?Jl("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(n):e.set(n,t),le=(n,e,t,r)=>(da(n,e,"write to private field"),r?r.call(n,t):e.set(n,t),t),ut=(n,e,t)=>(da(n,e,"access private method"),t);var Li=(n,e,t,r)=>({set _(o){le(n,e,o,t)},get _(){return O(n,e,r)}});(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))r(o);new MutationObserver(o=>{for(const i of o)if(i.type==="childList")for(const s of i.addedNodes)s.tagName==="LINK"&&s.rel==="modulepreload"&&r(s)}).observe(document,{childList:!0,subtree:!0});function t(o){const i={};return o.integrity&&(i.integrity=o.integrity),o.referrerPolicy&&(i.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?i.credentials="include":o.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function r(o){if(o.ep)return;o.ep=!0;const i=t(o);fetch(o.href,i)}})();/** +* @vue/shared v3.5.34 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/function Nc(n){const e=Object.create(null);for(const t of n.split(","))e[t]=1;return t=>t in e}const De={},ao=[],Sn=()=>{},mh=()=>!1,Is=n=>n.charCodeAt(0)===111&&n.charCodeAt(1)===110&&(n.charCodeAt(2)>122||n.charCodeAt(2)<97),Rs=n=>n.startsWith("onUpdate:"),it=Object.assign,Mc=(n,e)=>{const t=n.indexOf(e);t>-1&&n.splice(t,1)},pm=Object.prototype.hasOwnProperty,Pe=(n,e)=>pm.call(n,e),ie=Array.isArray,co=n=>Ai(n)==="[object Map]",yh=n=>Ai(n)==="[object Set]",Xl=n=>Ai(n)==="[object Date]",fe=n=>typeof n=="function",Be=n=>typeof n=="string",Vt=n=>typeof n=="symbol",Ne=n=>n!==null&&typeof n=="object",Ch=n=>(Ne(n)||fe(n))&&fe(n.then)&&fe(n.catch),vh=Object.prototype.toString,Ai=n=>vh.call(n),mm=n=>Ai(n).slice(8,-1),Th=n=>Ai(n)==="[object Object]",ks=n=>Be(n)&&n!=="NaN"&&n[0]!=="-"&&""+parseInt(n,10)===n,zo=Nc(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),Os=n=>{const e=Object.create(null);return t=>e[t]||(e[t]=n(t))},ym=/-\w/g,Ot=Os(n=>n.replace(ym,e=>e.slice(1).toUpperCase())),Cm=/\B([A-Z])/g,Cr=Os(n=>n.replace(Cm,"-$1").toLowerCase()),Ps=Os(n=>n.charAt(0).toUpperCase()+n.slice(1)),ha=Os(n=>n?`on${Ps(n)}`:""),wn=(n,e)=>!Object.is(n,e),Ji=(n,...e)=>{for(let t=0;t
$1');/^###? (.+)/.test(we)?(Z&&(U.push(""),Z=!1),U.push(`${we.replace(/^###? /,"")}
`)):/^# (.+)/.test(we)?(Z&&(U.push(""),Z=!1),U.push(`${we.replace(/^# /,"")}
`)):/^- (.+)/.test(we)?(Z||(U.push('${we}
`))}return Z&&U.push(""),U.join("")}async function C(){try{const S=await fetch("/cc-dashboard/api/assistant/history?limit=30",{headers:{Authorization:`Bearer ${e.token}`}});if(!S.ok)return;r.value=await S.json()}catch{}}async function p(){try{const S=await fetch("/cc-dashboard/api/assistant/flags?days_back=7&resolved=false",{headers:{Authorization:`Bearer ${e.token}`}});if(!S.ok)return;const x=await S.json();c.value=x.length}catch{}}async function v(){await fetch("/cc-dashboard/api/assistant/history",{method:"DELETE",headers:{Authorization:`Bearer ${e.token}`}}),r.value=[]}function A(){_("Show me all unresolved time-tracking issues from the last 7 days")}function _(S){o.value=S,y()}async function y(){const S=o.value.trim();if(!S||i.value)return;o.value="",Q();const x={id:crypto.randomUUID(),role:"user",content:S,created_at:new Date().toISOString()};r.value.push(x),T(),i.value=!0,s.value="",a.value=[];try{const V=await fetch("/cc-dashboard/api/assistant/chat",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.token}`},body:JSON.stringify({message:S})});if(!V.ok||!V.body)throw new Error(`HTTP ${V.status}`);const U=V.body.getReader(),Z=new TextDecoder;let ue="";for(;;){const{done:we,value:me}=await U.read();if(we)break;ue+=Z.decode(me,{stream:!0});const oe=ue.split(` +`);ue=oe.pop()??"";for(const ge of oe){if(!ge.startsWith("data: "))continue;const Re=ge.slice(6).trim();if(Re!=="[DONE]")try{const ve=JSON.parse(Re);ve.type==="text"?(s.value+=ve.text,T()):ve.type==="tool_start"?a.value.includes(ve.tool)||a.value.push(ve.tool):ve.type==="tool_result"?a.value=a.value.filter(ze=>ze!==ve.tool):ve.type==="error"&&(s.value=ve.text)}catch{}}}s.value&&r.value.push({id:crypto.randomUUID(),role:"assistant",content:s.value,created_at:new Date().toISOString()}),await p()}catch{r.value.push({id:crypto.randomUUID(),role:"assistant",content:"Failed to get response. Please try again.",created_at:new Date().toISOString()})}finally{i.value=!1,s.value="",a.value=[],T()}}function T(){Hr(()=>{l.value&&(l.value.scrollTop=l.value.scrollHeight)})}function P(S){const x=S.target;x.style.height="auto",x.style.height=`${Math.min(x.scrollHeight,96)}px`}function Q(){u.value&&(u.value.style.height="auto")}async function q(){t.value=!0,await C(),Hr(()=>{var S;return(S=u.value)==null?void 0:S.focus()}),T()}let K;return li(()=>{p(),K=setInterval(p,5*60*1e3)}),Vc(()=>{K!==void 0&&clearInterval(K)}),fr(t,S=>{S&&p()}),(S,x)=>(se(),ye(Fe,null,[t.value?It("",!0):(se(),ye("button",{key:0,class:"fixed bottom-6 right-6 z-50 flex h-14 w-14 items-center justify-center rounded-full bg-amber-400 text-gray-900 shadow-lg hover:bg-amber-300 transition-all duration-200 hover:scale-105 active:scale-95",title:"AI Assistant","aria-label":"Open AI Assistant",onClick:q},[x[2]||(x[2]=te("svg",{xmlns:"http://www.w3.org/2000/svg",class:"h-7 w-7",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor","stroke-width":"2"},[te("path",{"stroke-linecap":"round","stroke-linejoin":"round",d:"M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z"})],-1)),c.value>0?(se(),ye("span",z_,nn(c.value>9?"9+":c.value),1)):It("",!0)])),Ge(vC,{name:"slide-up"},{default:or(()=>[t.value?(se(),ye("div",Q_,[te("div",W_,[x[6]||(x[6]=te("div",{class:"flex items-center gap-2"},[te("div",{class:"flex h-8 w-8 items-center justify-center rounded-full bg-amber-400"},[te("svg",{xmlns:"http://www.w3.org/2000/svg",class:"h-4 w-4 text-gray-900",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor","stroke-width":"2"},[te("path",{"stroke-linecap":"round","stroke-linejoin":"round",d:"M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z"})])]),te("div",null,[te("p",{class:"text-sm font-semibold text-white"},"Time Analyst"),te("p",{class:"text-xs text-gray-400"},"AI assistant")])],-1)),te("div",Y_,[c.value>0?(se(),ye("button",{key:0,class:"flex items-center gap-1 rounded-full bg-red-900/40 px-2 py-0.5 text-xs text-red-400 hover:bg-red-900/60 transition-colors",title:"View anomalies",onClick:A},[x[3]||(x[3]=te("svg",{xmlns:"http://www.w3.org/2000/svg",class:"h-3 w-3",viewBox:"0 0 20 20",fill:"currentColor"},[te("path",{"fill-rule":"evenodd",d:"M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z","clip-rule":"evenodd"})],-1)),hi(" "+nn(c.value)+" issue"+nn(c.value>1?"s":""),1)])):It("",!0),te("button",{class:"p-1.5 text-gray-400 hover:text-white transition-colors",title:"Clear history","aria-label":"Clear chat history",onClick:v},[...x[4]||(x[4]=[te("svg",{xmlns:"http://www.w3.org/2000/svg",class:"h-4 w-4",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor","stroke-width":"2"},[te("path",{"stroke-linecap":"round","stroke-linejoin":"round",d:"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"})],-1)])]),te("button",{class:"p-1.5 text-gray-400 hover:text-white transition-colors","aria-label":"Close assistant",onClick:x[0]||(x[0]=V=>t.value=!1)},[...x[5]||(x[5]=[te("svg",{xmlns:"http://www.w3.org/2000/svg",class:"h-4 w-4",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor","stroke-width":"2"},[te("path",{"stroke-linecap":"round","stroke-linejoin":"round",d:"M6 18L18 6M6 6l12 12"})],-1)])])])]),te("div",{ref_key:"messagesEl",ref:l,class:"flex-1 overflow-y-auto p-3 space-y-3 min-h-0"},[r.value.length===0&&!i.value?(se(),ye("div",J_,[x[7]||(x[7]=te("div",{class:"h-12 w-12 rounded-full bg-amber-400/10 flex items-center justify-center mb-3"},[te("svg",{xmlns:"http://www.w3.org/2000/svg",class:"h-6 w-6 text-amber-400",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor","stroke-width":"2"},[te("path",{"stroke-linecap":"round","stroke-linejoin":"round",d:"M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z"})])],-1)),x[8]||(x[8]=te("p",{class:"text-sm font-medium text-gray-300"},"Time Analyst",-1)),x[9]||(x[9]=te("p",{class:"text-xs text-gray-500 mt-1"},"Ask me about your hours, gaps, or missing time entries.",-1)),te("div",X_,[(se(),ye(Fe,null,ho(d,V=>te("button",{key:V,class:"rounded-full border border-gray-600 px-3 py-1.5 text-xs text-gray-400 hover:border-amber-400 hover:text-amber-400 transition-colors",onClick:U=>_(V)},nn(V),9,Z_)),64))])])):It("",!0),(se(!0),ye(Fe,null,ho(r.value,V=>(se(),ye(Fe,{key:V.id},[V.role==="user"?(se(),ye("div",eS,[te("div",tS,[te("p",nS,nn(V.content),1)])])):(se(),ye("div",rS,[te("div",oS,[te("div",{class:"text-sm text-gray-200 prose prose-sm prose-invert max-w-none",innerHTML:f(V.content)},null,8,iS)])]))],64))),128)),i.value||s.value?(se(),ye("div",sS,[te("div",aS,[a.value.length>0?(se(),ye("div",cS,[(se(!0),ye(Fe,null,ho(a.value,V=>(se(),ye("div",{key:V,class:"flex items-center gap-1.5 text-xs text-amber-400"},[x[10]||(x[10]=te("svg",{class:"h-3 w-3 animate-spin",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24"},[te("circle",{class:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor","stroke-width":"4"}),te("path",{class:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"})],-1)),hi(" "+nn(h(V)),1)]))),128))])):It("",!0),s.value?(se(),ye("div",{key:1,class:"text-sm text-gray-200 prose prose-sm prose-invert max-w-none",innerHTML:f(s.value)},null,8,lS)):(se(),ye("div",uS,[...x[11]||(x[11]=[te("span",{class:"h-1.5 w-1.5 rounded-full bg-gray-500 animate-bounce",style:{"animation-delay":"0ms"}},null,-1),te("span",{class:"h-1.5 w-1.5 rounded-full bg-gray-500 animate-bounce",style:{"animation-delay":"150ms"}},null,-1),te("span",{class:"h-1.5 w-1.5 rounded-full bg-gray-500 animate-bounce",style:{"animation-delay":"300ms"}},null,-1)])]))])])):It("",!0)],512),te("div",dS,[te("div",hS,[sy(te("textarea",{ref_key:"inputEl",ref:u,"onUpdate:modelValue":x[1]||(x[1]=V=>o.value=V),rows:"1",placeholder:"Ask about your time...",class:"flex-1 resize-none rounded-xl bg-gray-700 border border-gray-600 px-3 py-2 text-sm text-white placeholder-gray-500 focus:outline-none focus:border-amber-400 transition-colors max-h-24 overflow-y-auto",disabled:i.value,onKeydown:[Bu(Fu(y,["exact","prevent"]),["enter"]),Bu(Fu(()=>{},["shift","exact"]),["enter"])],onInput:P},null,40,fS),[[KC,o.value]]),te("button",{disabled:!o.value.trim()||i.value,class:"flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-xl bg-amber-400 text-gray-900 transition-all hover:bg-amber-300 disabled:opacity-40 disabled:cursor-not-allowed",onClick:y},[...x[12]||(x[12]=[te("svg",{xmlns:"http://www.w3.org/2000/svg",class:"h-4 w-4",viewBox:"0 0 20 20",fill:"currentColor"},[te("path",{d:"M10.894 2.553a1 1 0 00-1.788 0l-7 14a1 1 0 001.169 1.409l5-1.429A1 1 0 009 15.571V11a1 1 0 112 0v4.571a1 1 0 00.725.962l5 1.428a1 1 0 001.17-1.408l-7-14z"})],-1)])],8,gS)]),x[13]||(x[13]=te("p",{class:"mt-1.5 text-center text-xs text-gray-600"},"Enter to send · Shift+Enter for newline",-1))])])):It("",!0)]),_:1})],64))}}),mS=(n,e)=>{const t=n.__vccOpts||n;for(const[r,o]of e)t[r]=o;return t},yS=mS(pS,[["__scopeId","data-v-5b6580b3"]]),CS=$r({__name:"App",setup(n){const e=ca(),t=_e(()=>e.isAuthenticated);return(r,o)=>{const i=Iy("RouterView");return se(),ye(Fe,null,[Ge(i),t.value?(se(),An(yS,{key:0})):It("",!0),Ge(ht(kT),{position:"top-right","toast-options":{style:{background:"hsl(var(--card))",color:"hsl(var(--card-foreground))",border:"1px solid hsl(var(--border))"}}})],64)}}});/*! + * vue-router v4.6.4 + * (c) 2025 Eduardo San Martin Morote + * @license MIT + */const no=typeof document<"u";function rm(n){return typeof n=="object"||"displayName"in n||"props"in n||"__vccOpts"in n}function vS(n){return n.__esModule||n[Symbol.toStringTag]==="Module"||n.default&&rm(n.default)}const Oe=Object.assign;function xa(n,e){const t={};for(const r in e){const o=e[r];t[r]=un(o)?o.map(n):n(o)}return t}const oi=()=>{},un=Array.isArray;function Gd(n,e){const t={};for(const r in n)t[r]=r in e?e[r]:n[r];return t}const om=/#/g,TS=/&/g,wS=/\//g,AS=/=/g,ES=/\?/g,im=/\+/g,bS=/%5B/g,_S=/%5D/g,sm=/%5E/g,SS=/%60/g,am=/%7B/g,IS=/%7C/g,cm=/%7D/g,RS=/%20/g;function zl(n){return n==null?"":encodeURI(""+n).replace(IS,"|").replace(bS,"[").replace(_S,"]")}function kS(n){return zl(n).replace(am,"{").replace(cm,"}").replace(sm,"^")}function Sc(n){return zl(n).replace(im,"%2B").replace(RS,"+").replace(om,"%23").replace(TS,"%26").replace(SS,"`").replace(am,"{").replace(cm,"}").replace(sm,"^")}function OS(n){return Sc(n).replace(AS,"%3D")}function PS(n){return zl(n).replace(om,"%23").replace(ES,"%3F")}function NS(n){return PS(n).replace(wS,"%2F")}function Ci(n){if(n==null)return null;try{return decodeURIComponent(""+n)}catch{}return""+n}const MS=/\/$/,xS=n=>n.replace(MS,"");function La(n,e,t="/"){let r,o={},i="",s="";const a=e.indexOf("#");let c=e.indexOf("?");return c=a>=0&&c>a?-1:c,c>=0&&(r=e.slice(0,c),i=e.slice(c,a>0?a:e.length),o=n(i.slice(1))),a>=0&&(r=r||e.slice(0,a),s=e.slice(a,e.length)),r=HS(r??e,t),{fullPath:r+i+s,path:r,query:o,hash:Ci(s)}}function LS(n,e){const t=e.query?n(e.query):"";return e.path+(t&&"?")+t+(e.hash||"")}function Vd(n,e){return!e||!n.toLowerCase().startsWith(e.toLowerCase())?n:n.slice(e.length)||"/"}function DS(n,e,t){const r=e.matched.length-1,o=t.matched.length-1;return r>-1&&r===o&&Po(e.matched[r],t.matched[o])&&lm(e.params,t.params)&&n(e.query)===n(t.query)&&e.hash===t.hash}function Po(n,e){return(n.aliasOf||n)===(e.aliasOf||e)}function lm(n,e){if(Object.keys(n).length!==Object.keys(e).length)return!1;for(var t in n)if(!US(n[t],e[t]))return!1;return!0}function US(n,e){return un(n)?zd(n,e):un(e)?zd(e,n):(n==null?void 0:n.valueOf())===(e==null?void 0:e.valueOf())}function zd(n,e){return un(e)?n.length===e.length&&n.every((t,r)=>t===e[r]):n.length===1&&n[0]===e}function HS(n,e){if(n.startsWith("/"))return n;if(!n)return e;const t=e.split("/"),r=n.split("/"),o=r[r.length-1];(o===".."||o===".")&&r.push("");let i=t.length-1,s,a;for(s=0;s$1');/^###? (.+)/.test(de)?(W&&(k.push(""),W=!1),k.push(`${de.replace(/^###? /,"")}
`)):/^# (.+)/.test(de)?(W&&(k.push(""),W=!1),k.push(`${de.replace(/^# /,"")}
`)):/^- (.+)/.test(de)?(W||(k.push('${de}
`))}return W&&k.push(""),k.join("")}async function x(){try{const S=await fetch("/cc-dashboard/api/assistant/history?limit=30",{headers:{Authorization:`Bearer ${t.token}`}});if(!S.ok)return;s.value=await S.json()}catch{}}async function m(){try{const S=await fetch("/cc-dashboard/api/assistant/flags?days_back=7&resolved=false",{headers:{Authorization:`Bearer ${t.token}`}});if(!S.ok)return;const I=await S.json();l.value=I.length}catch{}}async function w(){await fetch("/cc-dashboard/api/assistant/history",{method:"DELETE",headers:{Authorization:`Bearer ${t.token}`}}),s.value=[]}function E(){A("Show me all unresolved time-tracking issues from the last 7 days")}function A(S){r.value=S,y()}async function y(){const S=r.value.trim();if(!S||o.value)return;r.value="",K();const I={id:crypto.randomUUID(),role:"user",content:S,created_at:new Date().toISOString()};s.value.push(I),v(),o.value=!0,i.value="",a.value=[];try{const q=await fetch("/cc-dashboard/api/assistant/chat",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t.token}`},body:JSON.stringify({message:S})});if(!q.ok||!q.body)throw new Error(`HTTP ${q.status}`);const k=q.body.getReader(),W=new TextDecoder;let se="";for(;;){const{done:de,value:le}=await k.read();if(de)break;se+=W.decode(le,{stream:!0});const X=se.split(` -`);se=X.pop()??"";for(const ie of X){if(!ie.startsWith("data: "))continue;const ve=ie.slice(6).trim();if(ve!=="[DONE]")try{const ue=JSON.parse(ve);ue.type==="text"?(i.value+=ue.text,v()):ue.type==="tool_start"?a.value.includes(ue.tool)||a.value.push(ue.tool):ue.type==="tool_result"?a.value=a.value.filter(De=>De!==ue.tool):ue.type==="error"&&(i.value=ue.text)}catch{}}}i.value&&s.value.push({id:crypto.randomUUID(),role:"assistant",content:i.value,created_at:new Date().toISOString()}),await m()}catch{s.value.push({id:crypto.randomUUID(),role:"assistant",content:"Failed to get response. Please try again.",created_at:new Date().toISOString()})}finally{o.value=!1,i.value="",a.value=[],v()}}function v(){Hn(()=>{u.value&&(u.value.scrollTop=u.value.scrollHeight)})}function D(S){const I=S.target;I.style.height="auto",I.style.height=`${Math.min(I.scrollHeight,96)}px`}function K(){c.value&&(c.value.style.height="auto")}async function j(){n.value=!0,await x(),Hn(()=>{var S;return(S=c.value)==null?void 0:S.focus()}),v()}let B;return js(()=>{m(),B=setInterval(m,5*60*1e3)}),_i(()=>{B!==void 0&&clearInterval(B)}),wn(n,S=>{S&&m()}),(S,I)=>(ee(),ce(Ae,null,[n.value?st("",!0):(ee(),ce("button",{key:0,class:"fixed bottom-6 right-6 z-50 flex h-14 w-14 items-center justify-center rounded-full bg-amber-400 text-gray-900 shadow-lg hover:bg-amber-300 transition-all duration-200 hover:scale-105 active:scale-95",title:"AI Assistant","aria-label":"Open AI Assistant",onClick:j},[I[2]||(I[2]=J("svg",{xmlns:"http://www.w3.org/2000/svg",class:"h-7 w-7",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor","stroke-width":"2"},[J("path",{"stroke-linecap":"round","stroke-linejoin":"round",d:"M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z"})],-1)),l.value>0?(ee(),ce("span",Vm,Ct(l.value>9?"9+":l.value),1)):st("",!0)])),Te($d,{name:"slide-up"},{default:fn(()=>[n.value?(ee(),ce("div",$m,[J("div",Km,[I[6]||(I[6]=J("div",{class:"flex items-center gap-2"},[J("div",{class:"flex h-8 w-8 items-center justify-center rounded-full bg-amber-400"},[J("svg",{xmlns:"http://www.w3.org/2000/svg",class:"h-4 w-4 text-gray-900",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor","stroke-width":"2"},[J("path",{"stroke-linecap":"round","stroke-linejoin":"round",d:"M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z"})])]),J("div",null,[J("p",{class:"text-sm font-semibold text-white"},"Time Analyst"),J("p",{class:"text-xs text-gray-400"},"AI assistant")])],-1)),J("div",Qm,[l.value>0?(ee(),ce("button",{key:0,class:"flex items-center gap-1 rounded-full bg-red-900/40 px-2 py-0.5 text-xs text-red-400 hover:bg-red-900/60 transition-colors",title:"View anomalies",onClick:E},[I[3]||(I[3]=J("svg",{xmlns:"http://www.w3.org/2000/svg",class:"h-3 w-3",viewBox:"0 0 20 20",fill:"currentColor"},[J("path",{"fill-rule":"evenodd",d:"M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z","clip-rule":"evenodd"})],-1)),qs(" "+Ct(l.value)+" issue"+Ct(l.value>1?"s":""),1)])):st("",!0),J("button",{class:"p-1.5 text-gray-400 hover:text-white transition-colors",title:"Clear history","aria-label":"Clear chat history",onClick:w},[...I[4]||(I[4]=[J("svg",{xmlns:"http://www.w3.org/2000/svg",class:"h-4 w-4",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor","stroke-width":"2"},[J("path",{"stroke-linecap":"round","stroke-linejoin":"round",d:"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"})],-1)])]),J("button",{class:"p-1.5 text-gray-400 hover:text-white transition-colors","aria-label":"Close assistant",onClick:I[0]||(I[0]=q=>n.value=!1)},[...I[5]||(I[5]=[J("svg",{xmlns:"http://www.w3.org/2000/svg",class:"h-4 w-4",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor","stroke-width":"2"},[J("path",{"stroke-linecap":"round","stroke-linejoin":"round",d:"M6 18L18 6M6 6l12 12"})],-1)])])])]),J("div",{ref_key:"messagesEl",ref:u,class:"flex-1 overflow-y-auto p-3 space-y-3 min-h-0"},[s.value.length===0&&!o.value?(ee(),ce("div",zm,[I[7]||(I[7]=J("div",{class:"h-12 w-12 rounded-full bg-amber-400/10 flex items-center justify-center mb-3"},[J("svg",{xmlns:"http://www.w3.org/2000/svg",class:"h-6 w-6 text-amber-400",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor","stroke-width":"2"},[J("path",{"stroke-linecap":"round","stroke-linejoin":"round",d:"M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z"})])],-1)),I[8]||(I[8]=J("p",{class:"text-sm font-medium text-gray-300"},"Time Analyst",-1)),I[9]||(I[9]=J("p",{class:"text-xs text-gray-500 mt-1"},"Ask me about your hours, gaps, or missing time entries.",-1)),J("div",Wm,[(ee(),ce(Ae,null,ts(f,q=>J("button",{key:q,class:"rounded-full border border-gray-600 px-3 py-1.5 text-xs text-gray-400 hover:border-amber-400 hover:text-amber-400 transition-colors",onClick:k=>A(q)},Ct(q),9,Gm)),64))])])):st("",!0),(ee(!0),ce(Ae,null,ts(s.value,q=>(ee(),ce(Ae,{key:q.id},[q.role==="user"?(ee(),ce("div",Jm,[J("div",Ym,[J("p",Xm,Ct(q.content),1)])])):(ee(),ce("div",Zm,[J("div",ey,[J("div",{class:"text-sm text-gray-200 prose prose-sm prose-invert max-w-none",innerHTML:p(q.content)},null,8,ty)])]))],64))),128)),o.value||i.value?(ee(),ce("div",ny,[J("div",sy,[a.value.length>0?(ee(),ce("div",ry,[(ee(!0),ce(Ae,null,ts(a.value,q=>(ee(),ce("div",{key:q,class:"flex items-center gap-1.5 text-xs text-amber-400"},[I[10]||(I[10]=J("svg",{class:"h-3 w-3 animate-spin",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24"},[J("circle",{class:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor","stroke-width":"4"}),J("path",{class:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"})],-1)),qs(" "+Ct(h(q)),1)]))),128))])):st("",!0),i.value?(ee(),ce("div",{key:1,class:"text-sm text-gray-200 prose prose-sm prose-invert max-w-none",innerHTML:p(i.value)},null,8,oy)):(ee(),ce("div",iy,[...I[11]||(I[11]=[J("span",{class:"h-1.5 w-1.5 rounded-full bg-gray-500 animate-bounce",style:{"animation-delay":"0ms"}},null,-1),J("span",{class:"h-1.5 w-1.5 rounded-full bg-gray-500 animate-bounce",style:{"animation-delay":"150ms"}},null,-1),J("span",{class:"h-1.5 w-1.5 rounded-full bg-gray-500 animate-bounce",style:{"animation-delay":"300ms"}},null,-1)])]))])])):st("",!0)],512),J("div",ay,[J("div",ly,[Df(J("textarea",{ref_key:"inputEl",ref:c,"onUpdate:modelValue":I[1]||(I[1]=q=>r.value=q),rows:"1",placeholder:"Ask about your time...",class:"flex-1 resize-none rounded-xl bg-gray-700 border border-gray-600 px-3 py-2 text-sm text-white placeholder-gray-500 focus:outline-none focus:border-amber-400 transition-colors max-h-24 overflow-y-auto",disabled:o.value,onKeydown:[Oa(Ra(y,["exact","prevent"]),["enter"]),Oa(Ra(()=>{},["shift","exact"]),["enter"])],onInput:D},null,40,cy),[[dh,r.value]]),J("button",{disabled:!r.value.trim()||o.value,class:"flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-xl bg-amber-400 text-gray-900 transition-all hover:bg-amber-300 disabled:opacity-40 disabled:cursor-not-allowed",onClick:y},[...I[12]||(I[12]=[J("svg",{xmlns:"http://www.w3.org/2000/svg",class:"h-4 w-4",viewBox:"0 0 20 20",fill:"currentColor"},[J("path",{d:"M10.894 2.553a1 1 0 00-1.788 0l-7 14a1 1 0 001.169 1.409l5-1.429A1 1 0 009 15.571V11a1 1 0 112 0v4.571a1 1 0 00.725.962l5 1.428a1 1 0 001.17-1.408l-7-14z"})],-1)])],8,uy)]),I[13]||(I[13]=J("p",{class:"mt-1.5 text-center text-xs text-gray-600"},"Enter to send · Shift+Enter for newline",-1))])])):st("",!0)]),_:1})],64))}}),dy=(e,t)=>{const n=e.__vccOpts||e;for(const[s,r]of t)n[s]=r;return n},hy=dy(fy,[["__scopeId","data-v-5b6580b3"]]),py=Vn({__name:"App",setup(e){const t=so(),n=me(()=>t.isAuthenticated);return(s,r)=>{const o=Xf("RouterView");return ee(),ce(Ae,null,[Te(o),n.value?(ee(),Ut(hy,{key:0})):st("",!0),Te(Ke(eg),{position:"top-right","toast-options":{style:{background:"hsl(var(--card))",color:"hsl(var(--card-foreground))",border:"1px solid hsl(var(--border))"}}})],64)}}}),gy="modulepreload",my=function(e){return"/cc-dashboard/static/"+e},el={},ft=function(t,n,s){let r=Promise.resolve();if(n&&n.length>0){document.getElementsByTagName("link");const i=document.querySelector("meta[property=csp-nonce]"),a=(i==null?void 0:i.nonce)||(i==null?void 0:i.getAttribute("nonce"));r=Promise.allSettled(n.map(l=>{if(l=my(l),l in el)return;el[l]=!0;const u=l.endsWith(".css"),c=u?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${l}"]${c}`))return;const f=document.createElement("link");if(f.rel=u?"stylesheet":gy,u||(f.as="script"),f.crossOrigin="",f.href=l,a&&f.setAttribute("nonce",a),document.head.appendChild(f),u)return new Promise((h,p)=>{f.addEventListener("load",h),f.addEventListener("error",()=>p(new Error(`Unable to preload CSS for ${l}`)))})}))}function o(i){const a=new Event("vite:preloadError",{cancelable:!0});if(a.payload=i,window.dispatchEvent(a),!a.defaultPrevented)throw i}return r.then(i=>{for(const a of i||[])a.status==="rejected"&&o(a.reason);return t().catch(o)})};/*! - * vue-router v4.6.4 - * (c) 2025 Eduardo San Martin Morote - * @license MIT - */const Gn=typeof document<"u";function Ru(e){return typeof e=="object"||"displayName"in e||"props"in e||"__vccOpts"in e}function yy(e){return e.__esModule||e[Symbol.toStringTag]==="Module"||e.default&&Ru(e.default)}const we=Object.assign;function Ao(e,t){const n={};for(const s in t){const r=t[s];n[s]=Tt(r)?r.map(e):e(r)}return n}const Ls=()=>{},Tt=Array.isArray;function tl(e,t){const n={};for(const s in e)n[s]=s in t?t[s]:e[s];return n}const Ou=/#/g,vy=/&/g,by=/\//g,wy=/=/g,_y=/\?/g,Tu=/\+/g,xy=/%5B/g,Ey=/%5D/g,Pu=/%5E/g,Sy=/%60/g,Du=/%7B/g,Cy=/%7C/g,Nu=/%7D/g,Ay=/%20/g;function Li(e){return e==null?"":encodeURI(""+e).replace(Cy,"|").replace(xy,"[").replace(Ey,"]")}function Ry(e){return Li(e).replace(Du,"{").replace(Nu,"}").replace(Pu,"^")}function ni(e){return Li(e).replace(Tu,"%2B").replace(Ay,"+").replace(Ou,"%23").replace(vy,"%26").replace(Sy,"`").replace(Du,"{").replace(Nu,"}").replace(Pu,"^")}function Oy(e){return ni(e).replace(wy,"%3D")}function Ty(e){return Li(e).replace(Ou,"%23").replace(_y,"%3F")}function Py(e){return Ty(e).replace(by,"%2F")}function zs(e){if(e==null)return null;try{return decodeURIComponent(""+e)}catch{}return""+e}const Dy=/\/$/,Ny=e=>e.replace(Dy,"");function Ro(e,t,n="/"){let s,r={},o="",i="";const a=t.indexOf("#");let l=t.indexOf("?");return l=a>=0&&l>a?-1:l,l>=0&&(s=t.slice(0,l),o=t.slice(l,a>0?a:t.length),r=e(o.slice(1))),a>=0&&(s=s||t.slice(0,a),i=t.slice(a,t.length)),s=Fy(s??t,n),{fullPath:s+o+i,path:s,query:r,hash:zs(i)}}function Iy(e,t){const n=t.query?e(t.query):"";return t.path+(n&&"?")+n+(t.hash||"")}function nl(e,t){return!t||!e.toLowerCase().startsWith(t.toLowerCase())?e:e.slice(t.length)||"/"}function Ly(e,t,n){const s=t.matched.length-1,r=n.matched.length-1;return s>-1&&s===r&&hs(t.matched[s],n.matched[r])&&Iu(t.params,n.params)&&e(t.query)===e(n.query)&&t.hash===n.hash}function hs(e,t){return(e.aliasOf||e)===(t.aliasOf||t)}function Iu(e,t){if(Object.keys(e).length!==Object.keys(t).length)return!1;for(var n in e)if(!ky(e[n],t[n]))return!1;return!0}function ky(e,t){return Tt(e)?sl(e,t):Tt(t)?sl(t,e):(e==null?void 0:e.valueOf())===(t==null?void 0:t.valueOf())}function sl(e,t){return Tt(t)?e.length===t.length&&e.every((n,s)=>n===t[s]):e.length===1&&e[0]===t}function Fy(e,t){if(e.startsWith("/"))return e;if(!e)return t;const n=t.split("/"),s=e.split("/"),r=s[s.length-1];(r===".."||r===".")&&s.push("");let o=n.length-1,i,a;for(i=0;i