diff --git a/config/navigation.json b/config/navigation.json index a0ed1b8..2604d91 100644 --- a/config/navigation.json +++ b/config/navigation.json @@ -120,7 +120,8 @@ { "group": "Evaluation", "pages": [ - "tutorials/evaluate_trails_with_opa" + "tutorials/evaluate_trails_with_opa", + "tutorials/evaluate_policies_server_side" ] }, { diff --git a/images/tutorials/controls-coverage.png b/images/tutorials/controls-coverage.png new file mode 100644 index 0000000..e204fcc Binary files /dev/null and b/images/tutorials/controls-coverage.png differ diff --git a/images/tutorials/controls-decision-detail.png b/images/tutorials/controls-decision-detail.png index 6081e52..dd1aa5b 100644 Binary files a/images/tutorials/controls-decision-detail.png and b/images/tutorials/controls-decision-detail.png differ diff --git a/images/tutorials/controls-decisions.png b/images/tutorials/controls-decisions.png index c8c0e4f..0adb54b 100644 Binary files a/images/tutorials/controls-decisions.png and b/images/tutorials/controls-decisions.png differ diff --git a/images/tutorials/controls-list.png b/images/tutorials/controls-list.png index 7717b83..9f569ed 100644 Binary files a/images/tutorials/controls-list.png and b/images/tutorials/controls-list.png differ diff --git a/images/tutorials/policy-decision-detail.png b/images/tutorials/policy-decision-detail.png new file mode 100644 index 0000000..dfded4c Binary files /dev/null and b/images/tutorials/policy-decision-detail.png differ diff --git a/images/tutorials/policy-decisions.png b/images/tutorials/policy-decisions.png new file mode 100644 index 0000000..c63cf71 Binary files /dev/null and b/images/tutorials/policy-decisions.png differ diff --git a/images/tutorials/policy-list.png b/images/tutorials/policy-list.png new file mode 100644 index 0000000..ea5d1b8 Binary files /dev/null and b/images/tutorials/policy-list.png differ diff --git a/images/tutorials/policy-source.png b/images/tutorials/policy-source.png new file mode 100644 index 0000000..d194097 Binary files /dev/null and b/images/tutorials/policy-source.png differ diff --git a/mockups/policies-ui/.gitignore b/mockups/policies-ui/.gitignore new file mode 100644 index 0000000..f3f494d --- /dev/null +++ b/mockups/policies-ui/.gitignore @@ -0,0 +1,5 @@ +# generated by build.py + Chrome headless +# NB: the stylesheet must NOT be committed -- Mintlify auto-applies any .css in the project +kosli-mock.css +policy-*.html +policy-*.png diff --git a/mockups/policies-ui/README.md b/mockups/policies-ui/README.md new file mode 100644 index 0000000..0dea1c8 --- /dev/null +++ b/mockups/policies-ui/README.md @@ -0,0 +1,25 @@ +# Proposed Policies UI — wireframe mockups + +Sources for the mockup images used by +[`tutorials/evaluate_policies_server_side.mdx`](../../tutorials/evaluate_policies_server_side.mdx). +They depict a **proposed** UI that does not exist yet, so every rendered page carries a +"Mockup · proposed design" marker. + +Chrome and palette were matched against the real Controls screenshots in +`images/tutorials/controls-*.png` (sidebar `#101c2b`, primary `#1e55cd`, compliant `#3ca36f`, +non-compliant `#ce4a3e`). `logo.png` / `logo-footer.png` are crops of the real logo with the ICC +profile stripped, so they blend with the CSS colors. + +## Regenerate + +```bash +python3 build.py # also writes kosli-mock.css (gitignored) +for p in policy-list policy-source policy-decisions policy-decision-detail; do + "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \ + --headless=new --disable-gpu --hide-scrollbars --force-device-scale-factor=1 \ + --window-size=1535,1011 --screenshot="$p.png" "file://$PWD/$p.html" +done +cp policy-*.png ../../images/tutorials/ +``` + +1535x1011 at 1x matches the existing Controls screenshots. diff --git a/mockups/policies-ui/_chrome.html b/mockups/policies-ui/_chrome.html new file mode 100644 index 0000000..a9f0568 --- /dev/null +++ b/mockups/policies-ui/_chrome.html @@ -0,0 +1,24 @@ +
diff --git a/mockups/policies-ui/_footer.html b/mockups/policies-ui/_footer.html new file mode 100644 index 0000000..d1c7831 --- /dev/null +++ b/mockups/policies-ui/_footer.html @@ -0,0 +1,6 @@ + diff --git a/mockups/policies-ui/_topbar.html b/mockups/policies-ui/_topbar.html new file mode 100644 index 0000000..221ce3c --- /dev/null +++ b/mockups/policies-ui/_topbar.html @@ -0,0 +1,5 @@ + diff --git a/mockups/policies-ui/build.py b/mockups/policies-ui/build.py new file mode 100644 index 0000000..09aa301 --- /dev/null +++ b/mockups/policies-ui/build.py @@ -0,0 +1,464 @@ +#!/usr/bin/env python3 +"""Assemble the proposed-Policies-UI wireframe mockups from shared partials.""" +import pathlib, re + +HERE = pathlib.Path(__file__).parent + +CSS = r"""/* Wireframe mockup chrome for proposed Kosli Policies UI. + Palette sampled from real screenshots in images/tutorials/controls-*.png */ +* { box-sizing: border-box; margin: 0; padding: 0; } +:root { + --navy: #101c2b; + --ink: #14263a; + --grey: #6b7280; + --line: #e6e7e9; + --line-soft: #eef0f2; + --band: #f7f9fc; + --topbar: #f2f2f6; + --blue: #1e55cd; + --green: #3ca36f; + --red: #ce4a3e; + --chip: #eceef2; +} +body { + width: 1535px; min-height: 1011px; display: flex; + font: 400 15px/1.45 -apple-system, "Segoe UI", Inter, Helvetica, Arial, sans-serif; + color: var(--ink); background: #fcfcff; -webkit-font-smoothing: antialiased; +} + +/* ---------- sidebar ---------- */ +.sidebar { width: 250px; flex: 0 0 250px; background: var(--navy); padding: 16px 0 0; } +.logo { display: block; width: 130px; height: 48px; margin: 0 0 18px 10px; } +.org { display: flex; align-items: center; gap: 10px; color: #fff; font-weight: 600; + padding: 0 24px 0 20px; height: 34px; } +.org .home { opacity: .85; } +.org .name { flex: 1; } +.org .chev { opacity: .7; } +hr.sep { border: 0; border-top: 1px solid rgba(255,255,255,.16); margin: 14px 24px 12px; } +nav a { display: flex; align-items: center; gap: 14px; padding: 9px 20px; + color: #b9c2cd; text-decoration: none; font-size: 15px; } +nav a.on { color: #fff; font-weight: 600; } +nav svg { width: 19px; height: 19px; flex: 0 0 19px; } + +/* ---------- top bar ---------- */ +.main { flex: 1; min-width: 0; display: flex; flex-direction: column; } +.topbar { height: 51px; background: var(--topbar); display: flex; align-items: center; + padding: 0 22px 0 36px; gap: 14px; } +.crumb { font-size: 13.5px; color: var(--grey); flex: 1; } +.crumb b { color: var(--ink); } +.search { width: 278px; height: 32px; border: 1px solid #d8dbe0; border-radius: 999px; + background: #fff; display: flex; align-items: center; gap: 8px; padding: 0 14px; + font-size: 13px; color: #9aa1ab; } +.avatar { display: flex; align-items: center; gap: 5px; color: #5b6472; } +.avatar .ring { width: 26px; height: 26px; border-radius: 50%; background: #dfe3e9; + display: grid; place-items: center; } + +/* ---------- page ---------- */ +.page { flex: 1; padding: 26px 36px 0; } +h1 { font-size: 34px; font-weight: 700; letter-spacing: -.4px; line-height: 1.1; } +.h1row { display: flex; align-items: flex-start; gap: 12px; } +.sub { font-size: 16px; font-weight: 600; margin-top: 9px; } +.desc { font-size: 13.5px; color: var(--grey); margin-top: 6px; max-width: 1030px; } +.spacer { flex: 1; } +.toolrow { display: flex; align-items: center; gap: 10px; margin: 18px 0 22px; } + +/* ---------- controls ---------- */ +.field { width: 240px; height: 34px; border: 1px solid #d8dbe0; border-radius: 7px; + background: #fff; display: flex; align-items: center; gap: 8px; padding: 0 11px; + font-size: 13px; color: #9aa1ab; } +.btn { height: 34px; padding: 0 15px; border-radius: 7px; border: 1px solid #d8dbe0; + background: #fff; color: #374151; font-size: 13.5px; font-weight: 500; + display: inline-flex; align-items: center; gap: 7px; } +.btn.pri { background: var(--blue); border-color: var(--blue); color: #fff; font-weight: 600; } +.btn.danger { border-color: #ffdad5; color: #b4433a; } +.btn.sm { height: 27px; padding: 0 10px; font-size: 12.5px; border-radius: 6px; } + +.mock { margin-left: auto; align-self: flex-start; background: #fff7e6; border: 1px solid #f0d18a; + color: #8a6212; border-radius: 6px; font-size: 11.5px; font-weight: 600; + padding: 5px 10px; letter-spacing: .2px; white-space: nowrap; } + +/* ---------- tabs ---------- */ +.tabs { display: flex; gap: 4px; margin-top: 20px; } +.tab { display: flex; align-items: center; gap: 8px; padding: 9px 16px; font-size: 14px; + color: var(--grey); border: 1px solid transparent; border-radius: 8px 8px 0 0; } +.tab.on { background: #fff; border-color: var(--line); border-bottom-color: #fff; + color: var(--ink); font-weight: 600; } + +/* ---------- card ---------- */ +.card { border: 1px solid var(--line); border-radius: 10px; background: #fff; overflow: hidden; } +.card + .card { margin-top: 18px; } +.chead { background: var(--band); border-bottom: 1px solid var(--line); + display: flex; align-items: center; gap: 11px; padding: 13px 18px; font-size: 14.5px; + font-weight: 600; } +.count { background: var(--chip); color: #4b5563; border-radius: 6px; font-size: 12px; + font-weight: 600; padding: 2px 9px; } +.ctab { font-weight: 400; color: var(--grey); font-size: 14px; margin-left: 14px; } +.filters { margin-left: auto; display: flex; gap: 18px; font-size: 13px; color: #4b5563; + font-weight: 400; } +.row { display: flex; align-items: center; gap: 14px; padding: 14px 18px; + border-bottom: 1px solid var(--line-soft); } +.row:last-child { border-bottom: 0; } +.row .grow { flex: 1; min-width: 0; } +.id { font-size: 15px; font-weight: 700; } +.badge { display: inline-block; border: 1px solid #e2e4e8; background: #f7f8fa; color: #4b5563; + border-radius: 4px; font-size: 11px; font-weight: 600; padding: 1px 6px; + vertical-align: 2px; } +.name { font-weight: 400; } +.line2 { font-size: 13px; color: var(--grey); margin-top: 5px; } +.tags { display: flex; gap: 6px; margin-top: 8px; } +.tag { background: #eef2f7; color: #44526a; border-radius: 4px; font-size: 11px; + padding: 2px 8px; } +.kebab { color: #9aa1ab; font-size: 17px; line-height: 1; } +.pill { border-radius: 999px; color: #fff; font-size: 12.5px; font-weight: 600; + padding: 6px 15px 6px 11px; display: inline-flex; align-items: center; gap: 7px; + white-space: nowrap; } +.pill.ok { background: var(--green); } +.pill.no { background: var(--red); } +.pill .dot { width: 15px; height: 15px; border-radius: 50%; background: rgba(255,255,255,.28); + display: grid; place-items: center; font-size: 10px; } +.mono { font: 12.5px/1.55 ui-monospace, SFMono-Regular, Menlo, monospace; } +.hint { font-size: 13px; color: var(--grey); margin-top: 14px; } +.hint code { font: 12.5px ui-monospace, Menlo, monospace; background: #f3f4f6; + border-radius: 4px; padding: 1px 5px; } + +/* ---------- footer ---------- */ +footer { display: flex; align-items: center; gap: 18px; padding: 20px 36px 22px; + font-size: 12.5px; color: #4b5563; } +footer .gen { background: var(--chip); color: #6b7280; border-radius: 5px; font-size: 11px; + padding: 3px 9px; } +footer img { width: 82px; height: 34px; } +footer .links { display: flex; gap: 15px; color: var(--blue); } + +/* ---------- detail tray ---------- */ +.scrim { position: fixed; inset: 0; background: rgba(0,0,0,.5); } +.tray { position: fixed; top: 0; right: 0; bottom: 0; width: 843px; background: #fff; + display: flex; flex-direction: column; } +.thead { padding: 30px 32px 20px; } +.trow1 { display: flex; align-items: center; gap: 16px; } +.trow1 h2 { font-size: 30px; font-weight: 700; letter-spacing: -.3px; } +.close { margin-left: auto; color: #6b7280; font-size: 22px; line-height: 1; } +.tmeta { display: flex; align-items: center; gap: 12px; margin-top: 13px; font-size: 13.5px; + color: #4b5563; } +.kv { margin: 0 32px; border: 1px solid var(--line); border-radius: 8px; overflow: hidden; } +.kv > div { display: flex; border-bottom: 1px solid var(--line); } +.kv > div:last-child { border-bottom: 0; } +.kv dt { flex: 0 0 168px; background: var(--band); border-right: 1px solid var(--line); + padding: 13px 15px; font-size: 13.5px; color: var(--grey); } +.kv dd { flex: 1; min-width: 0; padding: 13px 15px; font-size: 13.5px; font-weight: 600; + word-break: break-all; } +.kv dd.plain { font-weight: 400; } +.kv dd ul { margin: 0; padding-left: 18px; font-weight: 400; } +.kv dd li + li { margin-top: 5px; } + +/* ---------- source view ---------- */ +.srcmeta { display: flex; gap: 26px; padding: 13px 18px; border-bottom: 1px solid var(--line-soft); + font-size: 13px; color: var(--grey); } +.srcmeta b { color: var(--ink); font-weight: 600; } +.src { display: flex; font: 12.5px/1.75 ui-monospace, SFMono-Regular, Menlo, monospace; } +.gutter { flex: 0 0 46px; text-align: right; padding: 14px 12px 16px 0; color: #b6bcc5; + background: #fcfcfd; border-right: 1px solid var(--line-soft); user-select: none; } +.code { flex: 1; padding: 14px 0 16px 16px; white-space: pre; overflow: hidden; color: var(--ink); } +.k { color: #8250df; } +.s { color: #0a6e5c; } +.vsel { display: inline-flex; align-items: center; gap: 7px; border: 1px solid #d8dbe0; + background: #fff; border-radius: 6px; padding: 3px 9px; font-size: 12.5px; + font-weight: 500; color: #374151; } + +/* ---------- bundle: file tree + viewer ---------- */ +.bundle { display: flex; align-items: stretch; } +.files { flex: 0 0 252px; border-right: 1px solid var(--line); background: #fcfcfd; + padding: 14px 0 16px; } +.files .cap { font-size: 11px; font-weight: 700; letter-spacing: .6px; color: #9aa1ab; + padding: 0 16px 10px; } +.fi { display: flex; align-items: center; gap: 7px; padding: 6px 16px; font-size: 13px; + color: #374151; border-left: 2px solid transparent; } +.fi.sel { background: #eef3fd; border-left-color: var(--blue); color: var(--blue); + font-weight: 600; } +.fi.nest { padding-left: 34px; } +.fi .flag { margin-left: auto; font-size: 10.5px; color: #9aa1ab; font-weight: 400; } +.dir { padding: 7px 16px 3px; font-size: 13px; color: #6b7280; } +.files .tot { border-top: 1px solid var(--line-soft); margin-top: 12px; padding: 11px 16px 0; + font-size: 12px; color: #9aa1ab; } +.viewer { flex: 1; min-width: 0; } +.vhead { display: flex; align-items: baseline; gap: 12px; padding: 13px 18px; + border-bottom: 1px solid var(--line-soft); font-size: 13.5px; } +.vhead .fn { font-weight: 700; font-size: 14px; } +.vhead .ep { background: #eef3fd; color: var(--blue); border-radius: 4px; font-size: 11px; + font-weight: 600; padding: 2px 7px; } +.vhead .meta { margin-left: auto; color: var(--grey); font-size: 12.5px; } +""" + +(HERE / "kosli-mock.css").write_text(CSS) +chrome = (HERE / "_chrome.html").read_text() +topbar = (HERE / "_topbar.html").read_text() +footer = (HERE / "_footer.html").read_text() + +ICON = ('') +CHEV = ' ▾' +TICK = '✓' +CROSS = '✕' + + +def shell(crumb, body, title): + return f"""kosli create policy --type rego). In the beta the UI is read-only,
+ apart from tagging.kosli create policy — the version shown is the one that runs
+ when an evaluation names this policy. Tests are stored with the bundle for audit but are not
+ executed server-side.