Implements Phases 1-8 of the TFTSR implementation plan. Rust backend (Tauri 2.x, src-tauri/): - Multi-provider AI: OpenAI-compatible, Anthropic, Gemini, Mistral, Ollama - PII detection engine: 11 regex patterns with overlap resolution - SQLCipher AES-256 encrypted database with 10 versioned migrations - 28 Tauri IPC commands for triage, analysis, document, and system ops - Ollama: hardware probe, model recommendations, pull/delete with events - RCA and blameless post-mortem Markdown document generators - PDF export via printpdf - Audit log: SHA-256 hash of every external data send - Integration stubs for Confluence, ServiceNow, Azure DevOps (v0.2) Frontend (React 18 + TypeScript + Vite, src/): - 9 pages: full triage workflow NewIssue→LogUpload→Triage→Resolution→RCA→Postmortem→History+Settings - 7 components: ChatWindow, TriageProgress, PiiDiffViewer, DocEditor, HardwareReport, ModelSelector, UI primitives - 3 Zustand stores: session, settings (persisted), history - Type-safe tauriCommands.ts matching Rust backend types exactly - 8 IT domain system prompts (Linux, Windows, Network, K8s, DB, Virt, HW, Obs) DevOps: - .woodpecker/test.yml: rustfmt, clippy, cargo test, tsc, vitest on every push - .woodpecker/release.yml: linux/amd64 + linux/arm64 builds, Gogs release upload Verified: - cargo check: zero errors - tsc --noEmit: zero errors - vitest run: 13/13 unit tests passing Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
299 lines
3.9 KiB
CSS
299 lines
3.9 KiB
CSS
/* Base */
|
|
|
|
body,
|
|
html {
|
|
margin: 0;
|
|
padding: 0;
|
|
height: 100%;
|
|
}
|
|
|
|
body {
|
|
color: #333;
|
|
background-color: #fcfcfc;
|
|
font: 14px/14px -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI',
|
|
Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
}
|
|
|
|
button {
|
|
margin: 0;
|
|
border: none;
|
|
font: inherit;
|
|
color: inherit;
|
|
}
|
|
|
|
button:focus {
|
|
outline: none;
|
|
}
|
|
|
|
*,
|
|
*:after,
|
|
*:before {
|
|
-webkit-box-sizing: border-box;
|
|
-moz-box-sizing: border-box;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
/* Typography */
|
|
|
|
h1 {
|
|
font-size: 20px;
|
|
line-height: 20px;
|
|
margin: 0;
|
|
}
|
|
|
|
a {
|
|
color: #0074d9;
|
|
text-decoration: none;
|
|
}
|
|
|
|
a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.small {
|
|
font-size: 12px;
|
|
}
|
|
|
|
.strong {
|
|
font-weight: bold;
|
|
}
|
|
|
|
.center {
|
|
text-align: center;
|
|
}
|
|
|
|
.quiet {
|
|
opacity: 0.7;
|
|
}
|
|
|
|
/* Colors */
|
|
|
|
.low {
|
|
background: #fce1e5;
|
|
}
|
|
|
|
.low--dark {
|
|
background: #c21f39;
|
|
}
|
|
|
|
.medium {
|
|
background: #fff4c2;
|
|
}
|
|
|
|
.medium--dark {
|
|
background: #f9cd0b;
|
|
}
|
|
|
|
.high {
|
|
background: rgb(230, 245, 208);
|
|
}
|
|
|
|
.high--dark {
|
|
background: rgb(77, 146, 33);
|
|
}
|
|
|
|
/* App */
|
|
|
|
.app {
|
|
height: 100%;
|
|
}
|
|
|
|
/* Layout */
|
|
|
|
.layout {
|
|
display: flex;
|
|
flex-direction: column;
|
|
min-height: 100%;
|
|
padding: 20px;
|
|
}
|
|
|
|
.layout__section {
|
|
flex-grow: 0;
|
|
}
|
|
|
|
.layout__section--fill {
|
|
flex-grow: 1;
|
|
}
|
|
|
|
.layout__section + .layout__section {
|
|
margin-top: 20px;
|
|
}
|
|
|
|
@media only screen and (max-width: 640px) {
|
|
.col3 {
|
|
width: 100%;
|
|
max-width: 100%;
|
|
}
|
|
.hide-mobile {
|
|
display: none !important;
|
|
}
|
|
}
|
|
|
|
/* Toolbar */
|
|
|
|
.toolbar {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.toolbar__item {
|
|
margin-right: 40px;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
/* Toggle */
|
|
|
|
.toggle {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.toggle__label {
|
|
margin-right: 0.5em;
|
|
}
|
|
|
|
.toggle__options {
|
|
display: inline-block;
|
|
border: 1px solid #0074d9;
|
|
border-radius: 4px;
|
|
color: #0074d9;
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.toggle__option {
|
|
padding: 4px 8px;
|
|
background: #fcfcfc;
|
|
}
|
|
|
|
.toggle__option + .toggle__option {
|
|
border-left: 1px solid #0074d9;
|
|
}
|
|
|
|
.toggle__option.is-toggled {
|
|
color: #fff;
|
|
background: #0074d9;
|
|
border-left-color: #fcfcfc;
|
|
}
|
|
|
|
/* Expand */
|
|
|
|
.expandbutton {
|
|
display: inline-block;
|
|
width: 1em;
|
|
margin-right: 0.25em;
|
|
padding: 0;
|
|
background-color: transparent;
|
|
font-weight: bold;
|
|
}
|
|
|
|
/* Fraction */
|
|
|
|
.fraction {
|
|
font-size: 12px;
|
|
color: #666;
|
|
padding: 2px 4px;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
/* Coverage */
|
|
|
|
.coverage-summary {
|
|
border-collapse: collapse;
|
|
}
|
|
|
|
.coverage-summary tbody tr {
|
|
border-bottom: 1px solid #fff;
|
|
}
|
|
|
|
.coverage-summary td,
|
|
.coverage-summary th {
|
|
padding: 5px;
|
|
}
|
|
|
|
.coverage-summary th {
|
|
text-align: left;
|
|
font-weight: normal;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.coverage-summary th.abs,
|
|
.coverage-summary td.pct,
|
|
.coverage-summary td.abs {
|
|
text-align: right;
|
|
}
|
|
|
|
.coverage-summary th.file {
|
|
min-width: 300px;
|
|
text-align: left;
|
|
}
|
|
|
|
.coverage-summary td.file {
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.coverage-summary td.pct {
|
|
font-weight: 400;
|
|
}
|
|
|
|
.coverage-summary td.abs {
|
|
color: #666;
|
|
font-size: 12px;
|
|
}
|
|
|
|
.coverage-summary td.empty {
|
|
opacity: 0.5;
|
|
}
|
|
|
|
.coverage-summary .headercell {
|
|
border-top: 1px solid #eee;
|
|
text-align: right;
|
|
font-size: 12px;
|
|
color: #666;
|
|
}
|
|
|
|
.coverage-summary .headercell:nth-child(5n - 3),
|
|
.coverage-summary td:nth-child(5n - 3) {
|
|
border-left: 2px solid #fcfcfc;
|
|
padding-left: 2em;
|
|
}
|
|
|
|
.filetab {
|
|
display: inline-block;
|
|
width: 1em;
|
|
}
|
|
|
|
/* Sorter */
|
|
|
|
.sorter {
|
|
display: inline-block;
|
|
width: 7px;
|
|
height: 10px;
|
|
margin-left: 0.5em;
|
|
background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent;
|
|
}
|
|
|
|
.sorted .sorter {
|
|
background-position: 0 -20px;
|
|
}
|
|
|
|
.sorted-desc .sorter {
|
|
background-position: 0 -10px;
|
|
}
|
|
|
|
.sortable {
|
|
cursor: pointer;
|
|
}
|
|
|
|
/* Bar */
|
|
|
|
.bar {
|
|
width: 50px;
|
|
height: 5px;
|
|
background: #fff;
|
|
}
|
|
|
|
.bar__data {
|
|
height: 100%;
|
|
}
|