style(panel-access): modifying the form structure design
This commit is contained in:
1 parent
b16d19d68b
commit
f15253a874
1 file changed
+103
-84
@@ -3,9 +3,9 @@
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import {
|
||||
AlertTriangle,
|
||||
ChevronDown,
|
||||
Globe2,
|
||||
Loader2,
|
||||
RefreshCw,
|
||||
ShieldCheck,
|
||||
} from "lucide-react";
|
||||
import {
|
||||
@@ -72,9 +72,6 @@ export default function PanelAccessSettingsPanel({
|
||||
const selectedCapability = capabilities?.proxies.find(
|
||||
(proxy) => proxy.type === panelProxy,
|
||||
);
|
||||
const panelRoutePreview = panelDomain.trim()
|
||||
? `${panelDomain.trim()} -> ${panelProxy}`
|
||||
: "No custom panel domain configured";
|
||||
const canProvision = Boolean(
|
||||
panelDomain.trim() &&
|
||||
selectedCapability?.available &&
|
||||
@@ -140,18 +137,50 @@ export default function PanelAccessSettingsPanel({
|
||||
return (
|
||||
<div
|
||||
className="card"
|
||||
style={{ padding: 24, display: "flex", flexDirection: "column", gap: 20 }}
|
||||
style={{
|
||||
padding: 0,
|
||||
overflow: "hidden",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
gap: 16,
|
||||
flexWrap: "wrap",
|
||||
padding: "18px 22px",
|
||||
borderBottom: "1px solid var(--border)",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "flex-start",
|
||||
justifyContent: "space-between",
|
||||
gap: 12,
|
||||
flexWrap: "wrap",
|
||||
gap: 11,
|
||||
minWidth: 0,
|
||||
}}
|
||||
>
|
||||
<div style={{ minWidth: 0 }}>
|
||||
{/* <span
|
||||
style={{
|
||||
width: 22,
|
||||
height: 22,
|
||||
flexShrink: 0,
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
borderRadius: "50%",
|
||||
background: "var(--accent-blue)",
|
||||
color: "white",
|
||||
fontSize: 11,
|
||||
fontWeight: 800,
|
||||
}}
|
||||
>
|
||||
1
|
||||
</span> */}
|
||||
<div>
|
||||
<h2
|
||||
style={{
|
||||
display: "flex",
|
||||
@@ -163,7 +192,7 @@ export default function PanelAccessSettingsPanel({
|
||||
}}
|
||||
>
|
||||
<Globe2 size={16} color="var(--accent-green)" />
|
||||
Panel Access
|
||||
Configure Panel Domain
|
||||
</h2>
|
||||
<div
|
||||
style={{
|
||||
@@ -173,7 +202,9 @@ export default function PanelAccessSettingsPanel({
|
||||
lineHeight: 1.5,
|
||||
}}
|
||||
>
|
||||
Custom domain provisioning for the Doktainer panel
|
||||
Set your panel domain and reverse proxy. Doktainer will handle the
|
||||
rest.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span className="ui-badge badge-info">
|
||||
@@ -183,6 +214,14 @@ export default function PanelAccessSettingsPanel({
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
padding: 22,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 18,
|
||||
}}
|
||||
>
|
||||
{error ? (
|
||||
<div
|
||||
style={{
|
||||
@@ -238,8 +277,9 @@ export default function PanelAccessSettingsPanel({
|
||||
<div
|
||||
style={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: "repeat(auto-fit, minmax(240px, 1fr))",
|
||||
gap: 16,
|
||||
gridTemplateColumns: "repeat(auto-fit, minmax(280px, 1fr))",
|
||||
gap: 14,
|
||||
alignItems: "start",
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
@@ -250,65 +290,58 @@ export default function PanelAccessSettingsPanel({
|
||||
value={panelDomain}
|
||||
onChange={(event) => setPanelDomain(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: "repeat(auto-fit, minmax(240px, 1fr))",
|
||||
gap: 16,
|
||||
alignItems: "stretch",
|
||||
}}
|
||||
style={{ marginTop: 6, fontSize: 11, color: "var(--text-muted)" }}
|
||||
>
|
||||
Enter the domain used to open the Doktainer panel.
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<FieldLabel>Reverse Proxy</FieldLabel>
|
||||
<div
|
||||
className="ui-pill-switch"
|
||||
style={{
|
||||
border: "1px solid var(--border)",
|
||||
background: "var(--bg-input)",
|
||||
}}
|
||||
<FieldLabel>
|
||||
Reverse Proxy{" "}
|
||||
<span style={{ fontWeight: 500, color: "var(--text-muted)" }}>
|
||||
(Auto Detect)
|
||||
</span>
|
||||
</FieldLabel>
|
||||
<div style={{ position: "relative" }}>
|
||||
<select
|
||||
className="input"
|
||||
value={panelProxy}
|
||||
disabled={loadingCapabilities}
|
||||
onChange={(event) =>
|
||||
setPanelProxy(event.target.value as PanelAccessProxy)
|
||||
}
|
||||
style={{ width: "100%", appearance: "none", paddingRight: 34 }}
|
||||
>
|
||||
{proxyOptions.map((option) => {
|
||||
const active = panelProxy === option.value;
|
||||
const capability = capabilities?.proxies.find(
|
||||
(proxy) => proxy.type === option.value,
|
||||
);
|
||||
const disabled =
|
||||
loadingCapabilities ||
|
||||
!capability?.available ||
|
||||
!capability.supportsProvisioning;
|
||||
const available =
|
||||
capability?.available && capability.supportsProvisioning;
|
||||
return (
|
||||
<button
|
||||
<option
|
||||
key={option.value}
|
||||
type="button"
|
||||
onClick={() => {
|
||||
if (!disabled) setPanelProxy(option.value);
|
||||
}}
|
||||
disabled={disabled}
|
||||
title={capability?.reason ?? undefined}
|
||||
style={{
|
||||
minHeight: 34,
|
||||
flex: "1 1 120px",
|
||||
border: "none",
|
||||
borderRadius: 6,
|
||||
background: active ? "#1d4ed8" : "transparent",
|
||||
color: disabled
|
||||
? "var(--text-muted)"
|
||||
: active
|
||||
? "white"
|
||||
: "var(--text-secondary)",
|
||||
fontSize: 12,
|
||||
fontWeight: 700,
|
||||
cursor: disabled ? "not-allowed" : "pointer",
|
||||
opacity: disabled ? 0.55 : 1,
|
||||
}}
|
||||
value={option.value}
|
||||
disabled={!available}
|
||||
>
|
||||
{option.label}
|
||||
</button>
|
||||
{available ? " (Detected)" : " (Unavailable)"}
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
</select>
|
||||
<ChevronDown
|
||||
size={15}
|
||||
style={{
|
||||
position: "absolute",
|
||||
right: 11,
|
||||
top: "50%",
|
||||
transform: "translateY(-50%)",
|
||||
pointerEvents: "none",
|
||||
color: "var(--text-muted)",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{selectedCapability?.reason ? (
|
||||
<div
|
||||
@@ -323,14 +356,16 @@ export default function PanelAccessSettingsPanel({
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
minHeight: 62,
|
||||
minHeight: 74,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
gap: 12,
|
||||
padding: "11px 12px",
|
||||
gap: 16,
|
||||
padding: "13px 14px",
|
||||
border: "1px solid var(--border)",
|
||||
borderRadius: 8,
|
||||
background: "var(--bg-input)",
|
||||
@@ -348,7 +383,7 @@ export default function PanelAccessSettingsPanel({
|
||||
}}
|
||||
>
|
||||
<ShieldCheck size={14} color="var(--accent-green)" />
|
||||
Auto SSL
|
||||
HTTPS / SSL
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
@@ -357,7 +392,7 @@ export default function PanelAccessSettingsPanel({
|
||||
color: "var(--text-muted)",
|
||||
}}
|
||||
>
|
||||
Certbot or proxy-managed TLS
|
||||
Automatically provision SSL certificate
|
||||
</div>
|
||||
</div>
|
||||
<Toggle
|
||||
@@ -365,7 +400,6 @@ export default function PanelAccessSettingsPanel({
|
||||
onChange={() => setPanelAutoSsl((current) => !current)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{capabilities?.autoSsl.reason ? (
|
||||
<div
|
||||
style={{
|
||||
@@ -382,36 +416,20 @@ export default function PanelAccessSettingsPanel({
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
justifyContent: "flex-end",
|
||||
alignItems: "center",
|
||||
gap: 12,
|
||||
flexWrap: "wrap",
|
||||
padding: "12px 14px",
|
||||
border: "1px solid rgba(59,130,246,0.24)",
|
||||
borderRadius: 8,
|
||||
background: "rgba(59,130,246,0.07)",
|
||||
paddingTop: 2,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 8,
|
||||
minWidth: 0,
|
||||
color: "var(--text-secondary)",
|
||||
fontSize: 12,
|
||||
}}
|
||||
>
|
||||
<RefreshCw size={14} color="var(--accent-blue)" />
|
||||
<span>{panelRoutePreview}</span>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-primary"
|
||||
disabled={!canProvision}
|
||||
onClick={() => void provisionPanelDomain()}
|
||||
style={{
|
||||
minWidth: 168,
|
||||
minWidth: 164,
|
||||
opacity: canProvision ? 1 : 0.55,
|
||||
cursor: canProvision ? "pointer" : "not-allowed",
|
||||
}}
|
||||
@@ -422,10 +440,11 @@ export default function PanelAccessSettingsPanel({
|
||||
Provisioning
|
||||
</>
|
||||
) : (
|
||||
"Provision Panel Domain"
|
||||
"Configure Domain"
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user