snapshot: preserve app state before onboarding pdf layout restore
This commit is contained in:
@@ -134,9 +134,6 @@ textarea { min-height: 120px; font-family: ui-monospace, SFMono-Regular, Menlo,
|
|||||||
.hint { margin-top: 6px; color: #64748b; font-size: 12px; }
|
.hint { margin-top: 6px; color: #64748b; font-size: 12px; }
|
||||||
.toolbar { display: flex; justify-content: space-between; align-items: center; gap: 10px; margin-bottom: 10px; flex-wrap: wrap; }
|
.toolbar { display: flex; justify-content: space-between; align-items: center; gap: 10px; margin-bottom: 10px; flex-wrap: wrap; }
|
||||||
.switch { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
|
.switch { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
|
||||||
.switch .tab { border: 1px solid #c9d6e7; border-radius: 999px; padding: 8px 14px; text-decoration: none; color: #1f2f49; font-weight: 700; background: #f6f9ff; transition: background-color 180ms cubic-bezier(0.2, 0.8, 0.2, 1), border-color 180ms cubic-bezier(0.2, 0.8, 0.2, 1), color 180ms cubic-bezier(0.2, 0.8, 0.2, 1), transform 180ms cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 180ms cubic-bezier(0.2, 0.8, 0.2, 1); }
|
|
||||||
.switch .tab.active { background: #000078; color: #fff; border-color: #000078; }
|
|
||||||
.switch .tab:hover { transform: translateY(-1px); box-shadow: 0 8px 16px rgba(16, 32, 57, 0.06); }
|
|
||||||
.check-row { margin-top: 8px; display: flex; gap: 12px; flex-wrap: wrap; }
|
.check-row { margin-top: 8px; display: flex; gap: 12px; flex-wrap: wrap; }
|
||||||
.check-row label { display: inline-flex; align-items: center; gap: 6px; margin: 0; font-size: 13px; }
|
.check-row label { display: inline-flex; align-items: center; gap: 6px; margin: 0; font-size: 13px; }
|
||||||
.check-row input[type="checkbox"] { width: auto; }
|
.check-row input[type="checkbox"] { width: auto; }
|
||||||
|
|||||||
@@ -150,6 +150,183 @@ body {
|
|||||||
gap: 14px;
|
gap: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-workspace {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 280px minmax(0, 1fr);
|
||||||
|
gap: 18px;
|
||||||
|
align-items: start;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-sidebar {
|
||||||
|
position: sticky;
|
||||||
|
top: 18px;
|
||||||
|
display: grid;
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-sidebar-card {
|
||||||
|
padding: 16px;
|
||||||
|
border: 1px solid rgba(216, 226, 239, 0.94);
|
||||||
|
border-radius: 18px;
|
||||||
|
background:
|
||||||
|
radial-gradient(120% 120% at 100% 0%, rgba(31, 79, 214, 0.05), rgba(31, 79, 214, 0)),
|
||||||
|
var(--ds-surface-soft);
|
||||||
|
box-shadow: inset 0 1px 0 rgba(255,255,255,0.94), var(--ds-shadow-card);
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-sidebar-card h1,
|
||||||
|
.app-sidebar-card h2 {
|
||||||
|
margin: 6px 0 0;
|
||||||
|
color: var(--ds-ink-strong);
|
||||||
|
line-height: 1.08;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-sidebar-card p {
|
||||||
|
margin: 8px 0 0;
|
||||||
|
color: var(--ds-muted);
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.55;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-sidebar-eyebrow {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 24px;
|
||||||
|
padding: 0 9px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(0, 0, 120, 0.07);
|
||||||
|
color: var(--ds-brand-strong);
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 800;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-side-nav {
|
||||||
|
display: grid;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-side-link {
|
||||||
|
display: grid;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 14px 16px;
|
||||||
|
border: 1px solid rgba(216, 226, 239, 0.94);
|
||||||
|
border-radius: 16px;
|
||||||
|
background: linear-gradient(180deg, #fbfdff, #ffffff);
|
||||||
|
color: var(--ds-ink-strong);
|
||||||
|
text-decoration: none;
|
||||||
|
transition:
|
||||||
|
transform var(--ds-motion-fast) var(--ds-ease),
|
||||||
|
border-color var(--ds-motion-fast) var(--ds-ease),
|
||||||
|
box-shadow var(--ds-motion-fast) var(--ds-ease),
|
||||||
|
background var(--ds-motion-fast) var(--ds-ease);
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-side-link:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
border-color: #b8cae0;
|
||||||
|
box-shadow: var(--ds-shadow-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-side-link.is-active {
|
||||||
|
border-color: #9eb6d8;
|
||||||
|
background: linear-gradient(180deg, #eef5ff, #ffffff);
|
||||||
|
box-shadow: 0 12px 24px rgba(15, 23, 42, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-side-link-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-side-link-meta {
|
||||||
|
color: var(--ds-muted);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-sidebar-stats {
|
||||||
|
display: grid;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-side-stat {
|
||||||
|
display: grid;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-side-stat strong {
|
||||||
|
font-size: 22px;
|
||||||
|
line-height: 1;
|
||||||
|
color: #163566;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-side-stat span {
|
||||||
|
color: var(--ds-muted);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-flow-list {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: grid;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-flow-item {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: flex-start;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid rgba(216, 226, 239, 0.94);
|
||||||
|
border-radius: 14px;
|
||||||
|
background: linear-gradient(160deg, #f8faff, #fcfdff);
|
||||||
|
transition:
|
||||||
|
border-color var(--ds-motion-fast) var(--ds-ease),
|
||||||
|
transform var(--ds-motion-fast) var(--ds-ease),
|
||||||
|
box-shadow var(--ds-motion-fast) var(--ds-ease);
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-flow-item.is-active {
|
||||||
|
border-color: #9db4ff;
|
||||||
|
background: linear-gradient(160deg, #eaf0ff, #f4f7ff);
|
||||||
|
box-shadow: 0 6px 16px rgba(0, 0, 120, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-flow-item:hover {
|
||||||
|
border-color: #b2c3ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-flow-dot {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
border-radius: 999px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: rgba(0, 0, 120, 0.06);
|
||||||
|
border: 1px solid rgba(0, 0, 120, 0.14);
|
||||||
|
color: var(--ds-brand);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-flow-title {
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1d2c68;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-flow-sub {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--ds-muted);
|
||||||
|
}
|
||||||
|
|
||||||
.metric-grid {
|
.metric-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||||
@@ -226,6 +403,46 @@ table th {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-module-nav {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-module-link,
|
||||||
|
.tab {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 36px;
|
||||||
|
padding: 0 14px;
|
||||||
|
border: 1px solid #c6d1e1;
|
||||||
|
border-radius: 999px;
|
||||||
|
text-decoration: none;
|
||||||
|
color: #1c2a41;
|
||||||
|
background: #f8fbff;
|
||||||
|
font-weight: 700;
|
||||||
|
transition:
|
||||||
|
transform var(--ds-motion-fast) var(--ds-ease),
|
||||||
|
border-color var(--ds-motion-fast) var(--ds-ease),
|
||||||
|
background var(--ds-motion-fast) var(--ds-ease),
|
||||||
|
box-shadow var(--ds-motion-fast) var(--ds-ease);
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-module-link:hover,
|
||||||
|
.tab:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
border-color: #9db4d2;
|
||||||
|
box-shadow: 0 8px 16px rgba(16, 32, 57, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-module-link.is-active,
|
||||||
|
.tab.active {
|
||||||
|
background: linear-gradient(135deg, #0f3b7a 0%, #1759b8 100%);
|
||||||
|
color: #fff;
|
||||||
|
border-color: #1759b8;
|
||||||
|
}
|
||||||
|
|
||||||
.inline-action-form {
|
.inline-action-form {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
@@ -259,6 +476,17 @@ table th {
|
|||||||
color: #8e1e1e;
|
color: #8e1e1e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 980px) {
|
||||||
|
.app-workspace {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
padding: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-sidebar {
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.status-note-error + .status-note-error {
|
.status-note-error + .status-note-error {
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,108 +1,38 @@
|
|||||||
:root {
|
|
||||||
--off-ink: #182233;
|
|
||||||
--off-muted: #5e6f85;
|
|
||||||
--off-brand: #000078;
|
|
||||||
--off-brand-soft: #eef1ff;
|
|
||||||
--off-line: #d7dfeb;
|
|
||||||
--off-card: #ffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.offboarding-shell-body {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 290px 1fr;
|
|
||||||
gap: 16px;
|
|
||||||
padding: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.offboarding-panel,
|
|
||||||
.offboarding-main,
|
.offboarding-main,
|
||||||
.offboarding-search-card,
|
.offboarding-search-card,
|
||||||
.offboarding-section-card {
|
.offboarding-section-card {
|
||||||
background: var(--off-card);
|
background: #ffffff;
|
||||||
border: 1px solid var(--off-line);
|
border: 1px solid #d7dfeb;
|
||||||
box-shadow: 0 12px 28px rgba(30, 52, 87, 0.08);
|
box-shadow: 0 12px 28px rgba(30, 52, 87, 0.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
.offboarding-panel,
|
|
||||||
.offboarding-search-card,
|
.offboarding-search-card,
|
||||||
.offboarding-section-card {
|
.offboarding-section-card {
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.offboarding-panel {
|
.workflow-sidebar-card h1 {
|
||||||
padding: 18px;
|
|
||||||
height: fit-content;
|
|
||||||
position: sticky;
|
|
||||||
top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.offboarding-main {
|
|
||||||
padding: 22px;
|
|
||||||
border-radius: 16px;
|
|
||||||
background: linear-gradient(180deg, #ffffff 0%, #fbfdff 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.offboarding-panel h1 {
|
|
||||||
margin: 0 0 8px;
|
margin: 0 0 8px;
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
letter-spacing: -0.02em;
|
letter-spacing: -0.02em;
|
||||||
color: var(--off-ink);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.offboarding-sub {
|
.offboarding-sub {
|
||||||
margin: 0 0 16px;
|
margin: 0 0 16px;
|
||||||
color: var(--off-muted);
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 1.55;
|
line-height: 1.55;
|
||||||
}
|
}
|
||||||
|
|
||||||
.offboarding-step-list {
|
|
||||||
list-style: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
display: grid;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.offboarding-step-item {
|
|
||||||
display: flex;
|
|
||||||
gap: 10px;
|
|
||||||
align-items: flex-start;
|
|
||||||
border: 1px solid #d8e0f4;
|
|
||||||
border-radius: 12px;
|
|
||||||
padding: 10px;
|
|
||||||
background: linear-gradient(160deg, #f8faff, #fcfdff);
|
|
||||||
}
|
|
||||||
|
|
||||||
.offboarding-dot {
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
border-radius: 999px;
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
background: var(--off-brand-soft);
|
|
||||||
border: 1px solid #c4cdf7;
|
|
||||||
color: var(--off-brand);
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
.offboarding-step-title {
|
|
||||||
font-weight: 700;
|
|
||||||
color: #1d2c68;
|
|
||||||
margin-bottom: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.offboarding-step-sub {
|
|
||||||
font-size: 12px;
|
|
||||||
color: var(--off-muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
.offboarding-main form {
|
.offboarding-main form {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.workflow-form-main.offboarding-main {
|
||||||
|
padding: 22px;
|
||||||
|
border-radius: 16px;
|
||||||
|
background: linear-gradient(180deg, #ffffff 0%, #fbfdff 100%);
|
||||||
|
}
|
||||||
|
|
||||||
.offboarding-search-card {
|
.offboarding-search-card {
|
||||||
padding: 14px;
|
padding: 14px;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
@@ -269,16 +199,6 @@ textarea {
|
|||||||
color: #475569;
|
color: #475569;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 980px) {
|
|
||||||
.offboarding-shell-body {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
.offboarding-panel {
|
|
||||||
position: static;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 820px) {
|
@media (max-width: 820px) {
|
||||||
.grid {
|
.grid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
|
|||||||
@@ -1,61 +1,22 @@
|
|||||||
:root {
|
.workflow-sidebar-card h1 {
|
||||||
--bg-a: #d3e3ff;
|
|
||||||
--bg-b: #eef4ff;
|
|
||||||
--ink: #182233;
|
|
||||||
--muted: #5e6f85;
|
|
||||||
--brand: #000078;
|
|
||||||
--brand-soft: #eef1ff;
|
|
||||||
--line: #d7dfeb;
|
|
||||||
--danger: #c53030;
|
|
||||||
--warn-bg: #fff7ed;
|
|
||||||
--warn-border: #fdba74;
|
|
||||||
--card: #ffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shell-body {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 290px 1fr;
|
|
||||||
gap: 16px;
|
|
||||||
padding: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-wrap {
|
|
||||||
width: min(var(--app-shell-width), 100%);
|
|
||||||
margin: 0 auto 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.panel,
|
|
||||||
.main {
|
|
||||||
background: var(--card);
|
|
||||||
border: 1px solid var(--line);
|
|
||||||
border-radius: 16px;
|
|
||||||
box-shadow: 0 12px 28px rgba(30, 52, 87, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.panel {
|
|
||||||
padding: 18px;
|
|
||||||
height: fit-content;
|
|
||||||
position: sticky;
|
|
||||||
top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main {
|
|
||||||
padding: 22px;
|
|
||||||
background: linear-gradient(180deg, #ffffff 0%, #fbfdff 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
margin: 0 0 8px;
|
margin: 0 0 8px;
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
letter-spacing: -0.02em;
|
letter-spacing: -0.02em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sub {
|
.workflow-sidebar-card .sub {
|
||||||
margin: 0 0 16px;
|
margin: 0 0 16px;
|
||||||
color: var(--muted);
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.workflow-form-main {
|
||||||
|
padding: 22px;
|
||||||
|
border: 1px solid #d7dfeb;
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 12px 28px rgba(30, 52, 87, 0.08);
|
||||||
|
background: linear-gradient(180deg, #ffffff 0%, #fbfdff 100%);
|
||||||
|
}
|
||||||
|
|
||||||
.brand-logo {
|
.brand-logo {
|
||||||
width: 180px;
|
width: 180px;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
@@ -68,66 +29,15 @@ h1 {
|
|||||||
margin: 0 0 10px;
|
margin: 0 0 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.step-list {
|
.app-flow-item {
|
||||||
list-style: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
display: grid;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.step-item {
|
|
||||||
display: flex;
|
|
||||||
gap: 10px;
|
|
||||||
align-items: flex-start;
|
|
||||||
border: 1px solid #d8e0f4;
|
|
||||||
border-radius: 12px;
|
|
||||||
padding: 10px;
|
|
||||||
background: linear-gradient(160deg, #f8faff, #fcfdff);
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: border-color 0.15s ease, transform 0.08s ease, box-shadow 0.15s ease;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.step-item.active {
|
.app-flow-item:focus-visible {
|
||||||
border-color: #9db4ff;
|
|
||||||
background: linear-gradient(160deg, #eaf0ff, #f4f7ff);
|
|
||||||
box-shadow: 0 6px 16px rgba(0, 0, 120, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.step-item:hover {
|
|
||||||
border-color: #b2c3ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.step-item:focus-visible {
|
|
||||||
outline: 3px solid rgba(0, 0, 120, 0.18);
|
outline: 3px solid rgba(0, 0, 120, 0.18);
|
||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dot {
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
border-radius: 999px;
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
background: var(--brand-soft);
|
|
||||||
border: 1px solid #c4cdf7;
|
|
||||||
color: var(--brand);
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
.step-title {
|
|
||||||
font-weight: 700;
|
|
||||||
color: #1d2c68;
|
|
||||||
margin-bottom: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.step-sub {
|
|
||||||
font-size: 12px;
|
|
||||||
color: var(--muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
.page {
|
.page {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
@@ -632,12 +542,8 @@ select:focus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 920px) {
|
@media (max-width: 920px) {
|
||||||
.shell {
|
.workflow-form-main {
|
||||||
grid-template-columns: 1fr;
|
padding: 18px;
|
||||||
}
|
|
||||||
|
|
||||||
.panel {
|
|
||||||
position: static;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid-2 {
|
.grid-2 {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
(function () {
|
(function () {
|
||||||
const pages = Array.from(document.querySelectorAll('.page'));
|
const pages = Array.from(document.querySelectorAll('.page'));
|
||||||
const navItems = Array.from(document.querySelectorAll('.step-item'));
|
const navItems = Array.from(document.querySelectorAll('.app-flow-item'));
|
||||||
const btnPrev = document.getElementById('btn-prev');
|
const btnPrev = document.getElementById('btn-prev');
|
||||||
const btnNext = document.getElementById('btn-next');
|
const btnNext = document.getElementById('btn-next');
|
||||||
const btnSubmit = document.getElementById('btn-submit');
|
const btnSubmit = document.getElementById('btn-submit');
|
||||||
@@ -270,7 +270,7 @@
|
|||||||
|
|
||||||
function updateStep() {
|
function updateStep() {
|
||||||
pages.forEach((p, i) => p.classList.toggle('active', i === current));
|
pages.forEach((p, i) => p.classList.toggle('active', i === current));
|
||||||
navItems.forEach((n, i) => n.classList.toggle('active', i === current));
|
navItems.forEach((n, i) => n.classList.toggle('is-active', i === current));
|
||||||
btnPrev.disabled = current === 0;
|
btnPrev.disabled = current === 0;
|
||||||
const last = current === pages.length - 1;
|
const last = current === pages.length - 1;
|
||||||
btnNext.classList.toggle('hidden', last);
|
btnNext.classList.toggle('hidden', last);
|
||||||
|
|||||||
@@ -11,38 +11,38 @@
|
|||||||
{% block shell_body %}
|
{% block shell_body %}
|
||||||
{% include 'workflows/includes/app_header.html' with header_show_home=1 header_inside_shell=1 %}
|
{% include 'workflows/includes/app_header.html' with header_show_home=1 header_inside_shell=1 %}
|
||||||
|
|
||||||
<div class="builder-workspace">
|
<div class="builder-workspace app-workspace">
|
||||||
<aside class="builder-sidebar">
|
<aside class="builder-sidebar app-sidebar">
|
||||||
<div class="builder-sidebar-card">
|
<div class="builder-sidebar-card app-sidebar-card">
|
||||||
<span class="builder-sidebar-eyebrow">{% trans "Arbeitsbereich" %}</span>
|
<span class="builder-sidebar-eyebrow app-sidebar-eyebrow">{% trans "Arbeitsbereich" %}</span>
|
||||||
<h2>{% trans "Formularsteuerung" %}</h2>
|
<h2>{% trans "Formularsteuerung" %}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<nav class="builder-side-nav" aria-label="{% trans 'Builder Navigation' %}">
|
<nav class="builder-side-nav app-side-nav" aria-label="{% trans 'Builder Navigation' %}">
|
||||||
<a class="builder-side-link{% if active_module == 'structure' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=structure">
|
<a class="builder-side-link app-side-link{% if active_module == 'structure' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=structure">
|
||||||
<span class="builder-side-link-title">{% trans "Struktur & Reihenfolge" %}</span>
|
<span class="builder-side-link-title app-side-link-title">{% trans "Struktur & Reihenfolge" %}</span>
|
||||||
<span class="builder-side-link-meta">{{ columns|length }} {% trans "Abschnitte" %}</span>
|
<span class="builder-side-link-meta app-side-link-meta">{{ columns|length }} {% trans "Abschnitte" %}</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="builder-side-link{% if active_module == 'section-rules' or active_module == 'field-rules' or active_module == 'conditional-rules' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=field-rules">
|
<a class="builder-side-link app-side-link{% if active_module == 'section-rules' or active_module == 'field-rules' or active_module == 'conditional-rules' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=field-rules">
|
||||||
<span class="builder-side-link-title">{% trans "Sichtbarkeit & Regeln" %}</span>
|
<span class="builder-side-link-title app-side-link-title">{% trans "Sichtbarkeit & Regeln" %}</span>
|
||||||
<span class="builder-side-link-meta">{{ builder_summary.hidden_field_count }} {% trans "ausgeblendet" %}</span>
|
<span class="builder-side-link-meta app-side-link-meta">{{ builder_summary.hidden_field_count }} {% trans "ausgeblendet" %}</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="builder-side-link{% if active_module == 'options' or active_module == 'field-texts' or active_module == 'custom-sections' or active_module == 'custom-fields' or active_module == 'preview' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=options">
|
<a class="builder-side-link app-side-link{% if active_module == 'options' or active_module == 'field-texts' or active_module == 'custom-sections' or active_module == 'custom-fields' or active_module == 'preview' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=options">
|
||||||
<span class="builder-side-link-title">{% trans "Optionen & Texte" %}</span>
|
<span class="builder-side-link-title app-side-link-title">{% trans "Optionen & Texte" %}</span>
|
||||||
<span class="builder-side-link-meta">{{ builder_summary.custom_field_count }} {% trans "eigene Felder" %}</span>
|
<span class="builder-side-link-meta app-side-link-meta">{{ builder_summary.custom_field_count }} {% trans "eigene Felder" %}</span>
|
||||||
</a>
|
</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="builder-sidebar-card builder-sidebar-stats">
|
<div class="builder-sidebar-card builder-sidebar-stats app-sidebar-card app-sidebar-stats">
|
||||||
<div class="builder-side-stat">
|
<div class="builder-side-stat app-side-stat">
|
||||||
<strong>{{ builder_summary.configurable_field_count }}</strong>
|
<strong>{{ builder_summary.configurable_field_count }}</strong>
|
||||||
<span>{% trans "konfigurierbare Felder" %}</span>
|
<span>{% trans "konfigurierbare Felder" %}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="builder-side-stat">
|
<div class="builder-side-stat app-side-stat">
|
||||||
<strong>{{ builder_summary.custom_section_count }}</strong>
|
<strong>{{ builder_summary.custom_section_count }}</strong>
|
||||||
<span>{% trans "eigene Abschnitte" %}</span>
|
<span>{% trans "eigene Abschnitte" %}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="builder-side-stat">
|
<div class="builder-side-stat app-side-stat">
|
||||||
<strong>{{ builder_summary.custom_field_count }}</strong>
|
<strong>{{ builder_summary.custom_field_count }}</strong>
|
||||||
<span>{% trans "eigene Felder" %}</span>
|
<span>{% trans "eigene Felder" %}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -152,11 +152,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<nav class="builder-module-nav" aria-label="{% trans 'Regelmodule' %}">
|
<nav class="builder-module-nav app-module-nav" aria-label="{% trans 'Regelmodule' %}">
|
||||||
<a class="builder-module-link{% if active_module == 'section-rules' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=section-rules">{% trans "Abschnitte" %}</a>
|
<a class="builder-module-link app-module-link{% if active_module == 'section-rules' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=section-rules">{% trans "Abschnitte" %}</a>
|
||||||
<a class="builder-module-link{% if active_module == 'field-rules' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=field-rules">{% trans "Feldregeln" %}</a>
|
<a class="builder-module-link app-module-link{% if active_module == 'field-rules' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=field-rules">{% trans "Feldregeln" %}</a>
|
||||||
{% if form_type == 'onboarding' %}
|
{% if form_type == 'onboarding' %}
|
||||||
<a class="builder-module-link{% if active_module == 'conditional-rules' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=conditional-rules">{% trans "Bedingte Logik" %}</a>
|
<a class="builder-module-link app-module-link{% if active_module == 'conditional-rules' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=conditional-rules">{% trans "Bedingte Logik" %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
@@ -441,14 +441,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<nav class="builder-module-nav" aria-label="{% trans 'Inhaltsmodule' %}">
|
<nav class="builder-module-nav app-module-nav" aria-label="{% trans 'Inhaltsmodule' %}">
|
||||||
<a class="builder-module-link{% if active_module == 'options' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=options">{% trans "Optionen" %}</a>
|
<a class="builder-module-link app-module-link{% if active_module == 'options' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=options">{% trans "Optionen" %}</a>
|
||||||
<a class="builder-module-link{% if active_module == 'field-texts' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=field-texts">{% trans "Feldtexte" %}</a>
|
<a class="builder-module-link app-module-link{% if active_module == 'field-texts' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=field-texts">{% trans "Feldtexte" %}</a>
|
||||||
{% if form_type == 'onboarding' %}
|
{% if form_type == 'onboarding' %}
|
||||||
<a class="builder-module-link{% if active_module == 'custom-sections' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=custom-sections">{% trans "Eigene Abschnitte" %}</a>
|
<a class="builder-module-link app-module-link{% if active_module == 'custom-sections' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=custom-sections">{% trans "Eigene Abschnitte" %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a class="builder-module-link{% if active_module == 'custom-fields' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=custom-fields">{% trans "Eigene Felder" %}</a>
|
<a class="builder-module-link app-module-link{% if active_module == 'custom-fields' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=custom-fields">{% trans "Eigene Felder" %}</a>
|
||||||
<a class="builder-module-link{% if active_module == 'preview' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=preview">{% trans "Vorschau" %}</a>
|
<a class="builder-module-link app-module-link{% if active_module == 'preview' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=preview">{% trans "Vorschau" %}</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="builder-stack-layout">
|
<div class="builder-stack-layout">
|
||||||
|
|||||||
@@ -37,57 +37,6 @@
|
|||||||
<main class="main">
|
<main class="main">
|
||||||
{% include 'workflows/includes/messages.html' %}
|
{% include 'workflows/includes/messages.html' %}
|
||||||
|
|
||||||
{% if ops_summary.show %}
|
|
||||||
<section class="ops-overview-card">
|
|
||||||
<div class="ops-overview-head">
|
|
||||||
<div>
|
|
||||||
<h2>{% trans "Operations Overview" %}</h2>
|
|
||||||
<p>{% trans "Letzte Laufzeit- und Backup-Signale auf einen Blick." %}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="ops-overview-grid">
|
|
||||||
{% if ops_summary.can_view_jobs %}
|
|
||||||
<article class="ops-stat-card">
|
|
||||||
<span class="ops-stat-label">{% trans "Fehlgeschlagene Jobs (24h)" %}</span>
|
|
||||||
<strong class="{% if ops_summary.failed_count_24h %}is-error{% endif %}">{{ ops_summary.failed_count_24h }}</strong>
|
|
||||||
</article>
|
|
||||||
<article class="ops-stat-card">
|
|
||||||
<span class="ops-stat-label">{% trans "Erfolgreiche Jobs (24h)" %}</span>
|
|
||||||
<strong>{{ ops_summary.success_count_24h }}</strong>
|
|
||||||
</article>
|
|
||||||
<article class="ops-stat-card">
|
|
||||||
<span class="ops-stat-label">{% trans "Offene Starts (24h)" %}</span>
|
|
||||||
<strong>{{ ops_summary.started_count_24h }}</strong>
|
|
||||||
</article>
|
|
||||||
{% endif %}
|
|
||||||
{% if ops_summary.can_manage_backups and ops_summary.backup_health %}
|
|
||||||
<article class="ops-stat-card">
|
|
||||||
<span class="ops-stat-label">{% trans "Backup-Status" %}</span>
|
|
||||||
<strong>{{ ops_summary.backup_health.label }}</strong>
|
|
||||||
<span class="mini">{{ ops_summary.backup_health.summary }}</span>
|
|
||||||
</article>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% if ops_summary.can_view_jobs and ops_summary.recent_failed_logs %}
|
|
||||||
<div class="ops-failure-list">
|
|
||||||
<div class="ops-failure-head">
|
|
||||||
<h3>{% trans "Letzte Fehler" %}</h3>
|
|
||||||
<a class="btn btn-secondary" href="/admin-tools/jobs/">{% trans "Job Monitor öffnen" %}</a>
|
|
||||||
</div>
|
|
||||||
<div class="ops-failure-items">
|
|
||||||
{% for log in ops_summary.recent_failed_logs %}
|
|
||||||
<article class="ops-failure-item">
|
|
||||||
<strong>{{ log.task_name }}</strong>
|
|
||||||
<span>{{ log.target_label|default:log.target_type }}</span>
|
|
||||||
<code>{{ log.error_message|truncatechars:120 }}</code>
|
|
||||||
</article>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</section>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% for section in portal_app_sections %}
|
{% for section in portal_app_sections %}
|
||||||
{% if not forloop.first %}
|
{% if not forloop.first %}
|
||||||
<div class="section-divider" aria-hidden="true"></div>
|
<div class="section-divider" aria-hidden="true"></div>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class="switch">
|
<div class="switch app-module-nav">
|
||||||
<a class="tab {% if kind == 'nextcloud' %}active{% endif %}" href="/admin-tools/integrations/?kind=nextcloud">{% trans "Setup Nextcloud" %}</a>
|
<a class="tab {% if kind == 'nextcloud' %}active{% endif %}" href="/admin-tools/integrations/?kind=nextcloud">{% trans "Setup Nextcloud" %}</a>
|
||||||
<a class="tab {% if kind == 'mail' %}active{% endif %}" href="/admin-tools/integrations/?kind=mail">{% trans "Setup Mail" %}</a>
|
<a class="tab {% if kind == 'mail' %}active{% endif %}" href="/admin-tools/integrations/?kind=mail">{% trans "Setup Mail" %}</a>
|
||||||
<a class="tab {% if kind == 'emails' %}active{% endif %}" href="/admin-tools/integrations/?kind=emails">{% trans "E-Mail Routing & Vorlagen" %}</a>
|
<a class="tab {% if kind == 'emails' %}active{% endif %}" href="/admin-tools/integrations/?kind=emails">{% trans "E-Mail Routing & Vorlagen" %}</a>
|
||||||
|
|||||||
@@ -37,6 +37,15 @@
|
|||||||
<label>{% trans "Offene Starts (24h)" %}</label>
|
<label>{% trans "Offene Starts (24h)" %}</label>
|
||||||
<div class="branding-inline-value">{{ job_summary.started_count_24h }}</div>
|
<div class="branding-inline-value">{{ job_summary.started_count_24h }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% if job_summary.can_manage_backups and job_summary.backup_health %}
|
||||||
|
<div class="field">
|
||||||
|
<label>{% trans "Backup-Status" %}</label>
|
||||||
|
<div class="branding-inline-value">
|
||||||
|
<strong>{{ job_summary.backup_health.label }}</strong>
|
||||||
|
<div class="mini">{{ job_summary.backup_health.summary }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% if job_summary.recent_failed %}
|
{% if job_summary.recent_failed %}
|
||||||
<div class="table-wrap u-mt-12 app-table-shell">
|
<div class="table-wrap u-mt-12 app-table-shell">
|
||||||
|
|||||||
@@ -20,24 +20,26 @@
|
|||||||
{% block shell_body %}
|
{% block shell_body %}
|
||||||
{% include 'workflows/includes/app_header.html' with header_show_lang=1 header_show_home=1 header_inside_shell=1 %}
|
{% include 'workflows/includes/app_header.html' with header_show_lang=1 header_show_home=1 header_inside_shell=1 %}
|
||||||
|
|
||||||
<div class="offboarding-shell-body">
|
<div class="app-workspace workflow-workspace">
|
||||||
<aside class="offboarding-panel">
|
<aside class="app-sidebar">
|
||||||
|
<div class="app-sidebar-card workflow-sidebar-card">
|
||||||
<h1>{% trans "Offboarding" %}</h1>
|
<h1>{% trans "Offboarding" %}</h1>
|
||||||
<p class="offboarding-sub">{% trans "Strukturierte Austrittsanfrage mit denselben klaren Oberflächenmustern wie im Onboarding." %}</p>
|
<p class="offboarding-sub">{% trans "Strukturierte Austrittsanfrage mit denselben klaren Oberflächenmustern wie im Onboarding." %}</p>
|
||||||
<ol class="offboarding-step-list">
|
<ol class="app-flow-list">
|
||||||
{% for section in offboarding_sections %}
|
{% for section in offboarding_sections %}
|
||||||
<li class="offboarding-step-item">
|
<li class="app-flow-item">
|
||||||
<span class="offboarding-dot">{{ forloop.counter }}</span>
|
<span class="app-flow-dot">{{ forloop.counter }}</span>
|
||||||
<div>
|
<div>
|
||||||
<div class="offboarding-step-title">{{ section.title }}</div>
|
<div class="app-flow-title">{{ section.title }}</div>
|
||||||
<div class="offboarding-step-sub">{{ section.subtitle }}</div>
|
<div class="app-flow-sub">{{ section.subtitle }}</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ol>
|
</ol>
|
||||||
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<main class="offboarding-main">
|
<main class="workflow-form-main offboarding-main">
|
||||||
<section class="offboarding-search-card">
|
<section class="offboarding-search-card">
|
||||||
<div class="offboarding-section-head offboarding-search-head">
|
<div class="offboarding-section-head offboarding-search-head">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -20,24 +20,26 @@
|
|||||||
{% block shell_body %}
|
{% block shell_body %}
|
||||||
{% include 'workflows/includes/app_header.html' with header_show_lang=1 header_show_home=1 header_inside_shell=1 %}
|
{% include 'workflows/includes/app_header.html' with header_show_lang=1 header_show_home=1 header_inside_shell=1 %}
|
||||||
|
|
||||||
<div class="shell-body">
|
<div class="app-workspace workflow-workspace">
|
||||||
<aside class="panel">
|
<aside class="app-sidebar">
|
||||||
|
<div class="app-sidebar-card workflow-sidebar-card">
|
||||||
<h1>{% trans "Onboarding" %}</h1>
|
<h1>{% trans "Onboarding" %}</h1>
|
||||||
<p class="sub">{% trans "Mehrseitiges Formular mit konfigurierbaren Feldern aus dem Admin." %}</p>
|
<p class="sub">{% trans "Mehrseitiges Formular mit konfigurierbaren Feldern aus dem Admin." %}</p>
|
||||||
<ol class="step-list">
|
<ol class="app-flow-list">
|
||||||
{% for section in onboarding_sections %}
|
{% for section in onboarding_sections %}
|
||||||
<li class="step-item {% if forloop.first %}active{% endif %}" data-nav-step="{{ forloop.counter }}" role="button" tabindex="0" aria-label="{{ section.title }}">
|
<li class="app-flow-item {% if forloop.first %}is-active{% endif %}" data-nav-step="{{ forloop.counter }}" role="button" tabindex="0" aria-label="{{ section.title }}">
|
||||||
<span class="dot">{{ forloop.counter }}</span>
|
<span class="app-flow-dot">{{ forloop.counter }}</span>
|
||||||
<div>
|
<div>
|
||||||
<div class="step-title">{{ section.title }}</div>
|
<div class="app-flow-title">{{ section.title }}</div>
|
||||||
<div class="step-sub">{{ section.subtitle }}</div>
|
<div class="app-flow-sub">{{ section.subtitle }}</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ol>
|
</ol>
|
||||||
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<main class="main">
|
<main class="workflow-form-main">
|
||||||
{% if form.errors %}
|
{% if form.errors %}
|
||||||
<div class="error-banner">{% trans "Bitte prüfen Sie die markierten Felder. Ungültige Eingaben wurden erkannt." %}</div>
|
<div class="error-banner">{% trans "Bitte prüfen Sie die markierten Felder. Ungültige Eingaben wurden erkannt." %}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class ObservabilityUITests(TestCase):
|
|||||||
)
|
)
|
||||||
return AsyncTaskLog.objects.get(id=log.id)
|
return AsyncTaskLog.objects.get(id=log.id)
|
||||||
|
|
||||||
def test_home_shows_operations_overview_for_admin(self):
|
def test_home_hides_operations_overview_for_admin(self):
|
||||||
self._create_log(
|
self._create_log(
|
||||||
status='failed',
|
status='failed',
|
||||||
task_name='send_scheduled_welcome_email',
|
task_name='send_scheduled_welcome_email',
|
||||||
@@ -63,11 +63,8 @@ class ObservabilityUITests(TestCase):
|
|||||||
response = client.get('/', HTTP_HOST='localhost')
|
response = client.get('/', HTTP_HOST='localhost')
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertContains(response, 'Operations Overview')
|
self.assertNotContains(response, 'Operations Overview')
|
||||||
self.assertContains(response, 'Fehlgeschlagene Jobs (24h)')
|
self.assertNotContains(response, 'Job Monitor öffnen')
|
||||||
self.assertContains(response, '<strong class="is-error">1</strong>', html=True)
|
|
||||||
self.assertContains(response, 'send_scheduled_welcome_email')
|
|
||||||
self.assertContains(response, 'Backup-Status')
|
|
||||||
|
|
||||||
def test_home_hides_operations_overview_for_staff(self):
|
def test_home_hides_operations_overview_for_staff(self):
|
||||||
self._create_log(
|
self._create_log(
|
||||||
@@ -113,6 +110,7 @@ class ObservabilityUITests(TestCase):
|
|||||||
self.assertContains(response, 'Offene Starts (24h)')
|
self.assertContains(response, 'Offene Starts (24h)')
|
||||||
self.assertContains(response, 'Zuletzt fehlgeschlagen')
|
self.assertContains(response, 'Zuletzt fehlgeschlagen')
|
||||||
self.assertContains(response, 'pdf failed')
|
self.assertContains(response, 'pdf failed')
|
||||||
|
self.assertContains(response, 'Backup-Status')
|
||||||
|
|
||||||
def test_job_monitor_requires_capability(self):
|
def test_job_monitor_requires_capability(self):
|
||||||
client = Client()
|
client = Client()
|
||||||
|
|||||||
@@ -743,7 +743,6 @@ def _ops_summary_for_user(user) -> dict[str, object]:
|
|||||||
def home(request):
|
def home(request):
|
||||||
config, _ = WorkflowConfig.objects.get_or_create(name='Default')
|
config, _ = WorkflowConfig.objects.get_or_create(name='Default')
|
||||||
role_key = get_user_role_key(request.user)
|
role_key = get_user_role_key(request.user)
|
||||||
ops_summary = _ops_summary_for_user(request.user)
|
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
'workflows/home.html',
|
'workflows/home.html',
|
||||||
@@ -754,7 +753,6 @@ def home(request):
|
|||||||
'role_label': get_user_role_label(request.user),
|
'role_label': get_user_role_label(request.user),
|
||||||
'role_key': role_key,
|
'role_key': role_key,
|
||||||
'portal_app_sections': build_portal_app_sections(request.user),
|
'portal_app_sections': build_portal_app_sections(request.user),
|
||||||
'ops_summary': ops_summary,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -789,6 +787,7 @@ def job_monitor_page(request):
|
|||||||
for row in recent_logs.values('status').annotate(count=Count('id'))
|
for row in recent_logs.values('status').annotate(count=Count('id'))
|
||||||
}
|
}
|
||||||
recent_failed = list(AsyncTaskLog.objects.filter(status='failed').order_by('-started_at', '-id')[:5])
|
recent_failed = list(AsyncTaskLog.objects.filter(status='failed').order_by('-started_at', '-id')[:5])
|
||||||
|
can_manage_backups = user_has_capability(request.user, 'manage_backups')
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
'workflows/job_monitor.html',
|
'workflows/job_monitor.html',
|
||||||
@@ -803,6 +802,8 @@ def job_monitor_page(request):
|
|||||||
'success_count_24h': counts.get('succeeded', 0),
|
'success_count_24h': counts.get('succeeded', 0),
|
||||||
'failed_count_24h': counts.get('failed', 0),
|
'failed_count_24h': counts.get('failed', 0),
|
||||||
'recent_failed': recent_failed,
|
'recent_failed': recent_failed,
|
||||||
|
'can_manage_backups': can_manage_backups,
|
||||||
|
'backup_health': latest_backup_health_snapshot() if can_manage_backups else None,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user