Backend: - Add AI assistant service with gap detection, anomaly analysis, Anthropic tool_use streaming - Add assistant router (chat SSE, history, flags CRUD, session categorization) - Fix agentic loop: text+tool_use in single assistant message per Anthropic spec - Migrate logging from stdlib to structlog in assistant modules - Fix migration 0005: UUID type for ai_flags/assistant_messages FKs Frontend: - Fix vite base path → /cc-dashboard/static/ to match FastAPI StaticFiles mount - Redesign Sidebar: gradient background, amber gradient active state, 44px touch targets, user avatar - Redesign KpiCard: corner decorations, ring border, trend icon, baseline bar (21st.dev pattern) - Redesign TopBar: backdrop-blur, sticky, gradient user avatar, sign-out button - Improve AssistantWidget: fix setInterval leak, aria-labels, proper markdown block parser - Fix AssistantWidget renderMarkdown: line-by-line parser for correct list/header nesting Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 line
6.4 KiB
JavaScript
1 line
6.4 KiB
JavaScript
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 j,D as K,K as m}from"./index-ZkX-rg-0.js";import{u as L}from"./devops-CMTMKOVx.js";import{_ as A,a as P}from"./CardContent.vue_vue_type_script_setup_true_lang-DGh5KRxz.js";import{_ as U,a as I}from"./CardTitle.vue_vue_type_script_setup_true_lang-CpwJW48B.js";import{_ as f}from"./Input.vue_vue_type_script_setup_true_lang-BzTd5oOE.js";import{_}from"./Button.vue_vue_type_script_setup_true_lang-CeodyRvV.js";import{i as O}from"./utils-DWBfPysr.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.org,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 N(){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 z(){if(!c.value||!p.value||!g.value){m.error("All ADO fields are required");return}b.value=!0;try{await t.saveIntegration({org: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(I,{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:N},{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(I,{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.org),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:z},{default:s(()=>[i(y(n(t).integration?"Update":"Connect"),1)]),_:1},8,["loading"]),n(t).integration?(x(),j(_,{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(),j(_,{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(I,{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};
|