From 444b5260b58a4dd89135dd0367341e85a48e72ca Mon Sep 17 00:00:00 2001 From: Jared Wolff Date: Thu, 5 Mar 2026 16:41:04 -0500 Subject: [PATCH] feat(profile): add App Passwords UI to profile page Add complete app password management UI with generate, copy, revoke functionality. Includes auto-generated client session passwords section, CSP-compliant event handlers, and dark mode support. --- TODO-LIST.md | 3 +- static/css/views/profile.css | 68 ++++++++++++++++++++++++++++++++++-- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/TODO-LIST.md b/TODO-LIST.md index 6e7cc813..8f1b8cf3 100755 --- a/TODO-LIST.md +++ b/TODO-LIST.md @@ -323,6 +323,7 @@ This document contains the task list for the development of OxiCloud, a minimali - [ ] Add scene and object detection in photos (beach, mountain, animals, etc.) - [ ] Implement similar or duplicate photo detection - [ ] Add non-destructive basic editing features (crop, filters, adjustments) + - [ ] Video support ### Enterprise Collaboration - [ ] Create shared workspaces @@ -390,4 +391,4 @@ This document contains the task list for the development of OxiCloud, a minimali - [ ] Implement legal hold - [ ] Develop case-based retention - [ ] Add evidence preservation - - [ ] Implement chain of custody \ No newline at end of file + - [ ] Implement chain of custody diff --git a/static/css/views/profile.css b/static/css/views/profile.css index f456713b..de9d4fed 100755 --- a/static/css/views/profile.css +++ b/static/css/views/profile.css @@ -4,7 +4,7 @@ body{background:#f5f7fa;color:#1e293b;min-height:100vh;height:auto;display:flex; .link-reset-flex{text-decoration:none;color:inherit;display:flex;align-items:center;gap:14px} .width-zero{width:0%} -#main-content{display:none} +/* #main-content and #auth-error start hidden via .hidden class */ /* ── Scrollbar ── */ ::-webkit-scrollbar{width:8px} @@ -104,11 +104,60 @@ body{background:#f5f7fa;color:#1e293b;min-height:100vh;height:auto;display:flex; .alert-success{background:#ecfdf5;color:#065f46;border:1px solid #a7f3d0} .alert-error{background:#fef2f2;color:#991b1b;border:1px solid #fecaca} +/* ── App Passwords ── */ +.section-desc{font-size:13px;color:#64748b;margin-bottom:16px;line-height:1.5} +.scope-checkboxes{display:flex;gap:16px;flex-wrap:wrap} +.checkbox-label{display:flex;align-items:center;gap:5px;font-size:13px;font-weight:500;color:#334155;cursor:pointer} +.checkbox-label input[type="checkbox"]{accent-color:#ff5e3a;width:16px;height:16px} +.form-select{ + width:100%;padding:10px 14px;border:2px solid #e2e8f0;border-radius:10px;font-size:14px; + background:#f8fafc;color:#1e293b;font-family:inherit;transition:all .2s;appearance:auto; +} +.form-select:focus{outline:none;border-color:#ff5e3a;background:#fff;box-shadow:0 0 0 3px rgba(255,94,58,.1)} +.btn-secondary{background:#f1f5f9;color:#334155;border:2px solid #e2e8f0} +.btn-secondary:hover{background:#e2e8f0} +.btn-danger{background:linear-gradient(135deg,#dc2626,#ef4444);color:#fff;box-shadow:0 2px 8px rgba(220,38,38,.2)} +.btn-danger:hover{box-shadow:0 4px 14px rgba(220,38,38,.3);transform:translateY(-1px)} +.btn-sm{padding:6px 12px;font-size:12px;border-radius:8px} + +.app-pw-table{width:100%;border-collapse:collapse;font-size:13px} +.app-pw-table th{text-align:left;font-size:11px;text-transform:uppercase;letter-spacing:.05em;color:#94a3b8;font-weight:700;padding:8px 10px;border-bottom:2px solid #e2e8f0} +.app-pw-table td{padding:10px;border-bottom:1px solid #f1f5f9;vertical-align:middle} +.app-pw-table tr:last-child td{border-bottom:none} +.app-pw-label-cell{font-weight:600;color:#1e293b} +.app-pw-prefix code{font-size:12px;background:#f1f5f9;padding:2px 8px;border-radius:6px;color:#64748b} + +.badge{display:inline-block;font-size:11px;font-weight:600;padding:2px 10px;border-radius:12px} +.badge-active{background:#ecfdf5;color:#065f46} +.badge-expired{background:#fef2f2;color:#991b1b} + +@media(max-width:640px){ + .app-pw-table{font-size:12px} + .app-pw-table th:nth-child(3),.app-pw-table td:nth-child(3), + .app-pw-table th:nth-child(5),.app-pw-table td:nth-child(5){display:none} +} +.app-pw-empty{text-align:center;padding:24px;color:#94a3b8;font-size:13px} +.app-pw-empty i{margin-right:6px} + +.hidden{display:none} +.app-pw-warn{margin-bottom:8px} +.app-pw-dismiss{margin-top:10px} +.app-pw-actions{display:flex;gap:8px} +.app-pw-new-btn{margin-top:14px} +.app-pw-created-box{position:relative} +.app-pw-token-row{display:flex;gap:8px;align-items:center;margin-bottom:8px} +.app-pw-token-input{ + flex:1;padding:10px 14px;border:2px solid #a7f3d0;border-radius:10px;font-size:14px; + font-family:'Courier New',Courier,monospace;background:#f0fdf4;color:#065f46; +} +.app-pw-instr-list{font-size:12px;line-height:1.8;margin-top:8px} +.app-pw-instr-list code{background:#f0fdf4;padding:1px 6px;border-radius:4px;font-size:12px} + /* ── Loading / Error ── */ #loading{text-align:center;padding:80px;color:#94a3b8;font-size:15px} #loading i{font-size:32px;color:#ff5e3a;display:block;margin-bottom:12px;animation:spin 1s linear infinite} @keyframes spin{to{transform:rotate(360deg)}} -#auth-error{display:none;text-align:center;padding:80px 20px} +#auth-error{text-align:center;padding:80px 20px} #auth-error .err-icon{width:80px;height:80px;background:#fef2f2;border-radius:50%;display:flex;align-items:center;justify-content:center;margin:0 auto 20px} #auth-error .err-icon i{font-size:32px;color:#ef4444} #auth-error h2{color:#991b1b;margin-bottom:8px;font-size:20px} @@ -190,6 +239,21 @@ body{background:#f5f7fa;color:#1e293b;min-height:100vh;height:auto;display:flex; [data-theme="dark"] #auth-error .err-icon{background:#3b1111} [data-theme="dark"] #auth-error h2{color:#fca5a5} [data-theme="dark"] #auth-error p{color:#94a3b8} +[data-theme="dark"] .section-desc{color:#64748b} +[data-theme="dark"] .checkbox-label{color:#94a3b8} +[data-theme="dark"] .form-select{background:#0f172a;border-color:#334155;color:#e2e8f0} +[data-theme="dark"] .form-select:focus{border-color:#ff5e3a;background:#0f172a;box-shadow:0 0 0 3px rgba(255,94,58,.15)} +[data-theme="dark"] .btn-secondary{background:#334155;color:#e2e8f0;border-color:#475569} +[data-theme="dark"] .btn-secondary:hover{background:#475569} +[data-theme="dark"] .app-pw-table th{color:#64748b;border-bottom-color:#334155} +[data-theme="dark"] .app-pw-table td{border-bottom-color:#1e293b} +[data-theme="dark"] .app-pw-label-cell{color:#f1f5f9} +[data-theme="dark"] .app-pw-prefix code{background:#334155;color:#94a3b8} +[data-theme="dark"] .badge-active{background:#052e16;color:#86efac} +[data-theme="dark"] .badge-expired{background:#3b1111;color:#fca5a5} +[data-theme="dark"] .app-pw-empty{color:#64748b} +[data-theme="dark"] .app-pw-token-input{background:#052e16;border-color:#065f46;color:#86efac} +[data-theme="dark"] .app-pw-instr-list code{background:#052e16;color:#86efac} [data-theme="dark"] #loading{color:#64748b} [data-theme="dark"] .app-pw-desc{color:#94a3b8} [data-theme="dark"] .app-pw-create input{background:#0f172a;border-color:#334155;color:#e2e8f0}