Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c4bc1d3
Change to new certs rest table API endpoint
mrmelon54 Nov 24, 2025
5dde767
Add certificate creation popup
mrmelon54 Nov 26, 2025
a8db4ef
Improve styling of dynamic list widget
mrmelon54 Nov 26, 2025
4a6fd72
Support adding values to the dynamic list when pressing enter
mrmelon54 Nov 26, 2025
cfdd03b
Only allow non empty trimmed domain names in a certificate
mrmelon54 Nov 26, 2025
46f8234
Try Tom Select
mrmelon54 Nov 26, 2025
6710211
Remove Tom Select to use standard HTML datalist instead
mrmelon54 Nov 27, 2025
e7cc051
Add IP addresses to certificate preview
mrmelon54 Nov 27, 2025
9a4c774
Add delete button to certificates
mrmelon54 Nov 27, 2025
a2636d9
Remove :last-child from .branch-cell in CertificiatesView
mrmelon54 Nov 27, 2025
7aecb74
Add name column to certificate list
mrmelon54 Nov 28, 2025
8867942
Add common name to client side certificate filtering
mrmelon54 Nov 29, 2025
fa47990
Set initial reduce value to false when filtering by domain
mrmelon54 Nov 29, 2025
75e08aa
Add support for patch API calls in rest table item
mrmelon54 Nov 29, 2025
c00cdbf
Add toggle icon in certificate auto renew column
mrmelon54 Nov 29, 2025
47df6d5
Format nested filter query in rowOrdering function
mrmelon54 Nov 29, 2025
bad7337
Add button element around certificate auto renew icon
mrmelon54 Nov 29, 2025
a3b4bf1
Always highlight the auto renew icon colour
mrmelon54 Nov 29, 2025
a6d8133
Add a div within the auto renew table cell
mrmelon54 Nov 29, 2025
5268128
Add an apiCall method to RestItem
mrmelon54 Nov 29, 2025
d77aa62
Remove the active column from the certificate table
mrmelon54 Nov 29, 2025
83be97c
Add a button to manual renew a certificate
mrmelon54 Nov 29, 2025
e703ae4
Change manual renew button to gold style
mrmelon54 Nov 29, 2025
ecdf3df
Add action row to allow actions to render horizontally
mrmelon54 Nov 29, 2025
d3322c6
Use right align on the action row buttons
mrmelon54 Nov 29, 2025
bb0e595
Add subject fields to test server response
mrmelon54 Nov 30, 2025
caf72e4
Add name field to test server
mrmelon54 Nov 30, 2025
de5c774
Work with certificates which are missing the subject object
mrmelon54 Dec 6, 2025
daec201
Ensure this does not crash if the domains are missing
mrmelon54 Dec 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@
"vite": "^4.4.5"
},
"dependencies": {
"countries-list": "^3.2.0",
"d3": "^7.9.0",
"downloadjs": "^1.4.7",
"ipaddr.js": "^2.2.0"
"ipaddr.js": "^2.2.0",
"tom-select": "^2.4.3"
},
"packageManager": "yarn@4.12.0+sha512.f45ab632439a67f8bc759bf32ead036a1f413287b9042726b7cc4818b7b49e14e9423ba49b18f9e06ea4941c1ad062385b1d8760a8d5091a1a31e5f6219afca8"
}
15 changes: 15 additions & 0 deletions src/components/CountrySelect.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<script lang="ts">
import {getCountryDataList} from "countries-list";

const countriesList = getCountryDataList().sort((a, b) => a.name.localeCompare(b.name));

export let value: string = "";
</script>

<input bind:value list="countries-list" {...$$restProps} />

<datalist id="countries-list">
{#each countriesList as country}
<option value={country.iso2}>{country.name}</option>
{/each}
</datalist>
82 changes: 82 additions & 0 deletions src/components/DynamicListView.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<script lang="ts">
import RemoveIcon from "../icons/Remove.svelte";

type T = $$Generic<Object>;

export let list: T[];
export let parser: (value: string) => T | null;
let addValue: string = "";

function addItem() {
let item = parser(addValue);
if (item == null) return;
list.push(item);
list = list;
addValue = "";
}

function removeItem(index: number) {
list.splice(index, 1);
list = list;
}
</script>

<div class="list-search">
<input
type="text"
bind:value={addValue}
on:keydown={e => {
if (e.key === "Enter") {
addItem();
}
}}
/>
<button on:click={() => addItem()}>Add</button>
</div>

<div class="list-view">
{#each list as item, i}
<div class="list-item">
<div class="content">{item}</div>
<button class="remove" on:click={() => removeItem(i)}><RemoveIcon /></button>
</div>
{/each}
</div>

<style lang="scss">
@import "../values.scss";

.list-search {
display: flex;
flex-direction: row;
gap: 8px;

input {
flex-grow: 1;
}
}

.list-view {
display: flex;
flex-direction: column;

.list-item {
display: flex;
flex-direction: row;
justify-content: space-between;

.content {
padding: 8px;
font-family: monospace;
}

&:hover {
background-color: #262626;
}

.remove {
@include button-red-highlight;
}
}
}
</style>
17 changes: 17 additions & 0 deletions src/icons/RefreshCW.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-refresh-cw-icon lucide-refresh-cw"
>
<path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8" />
<path d="M21 3v5h-5" />
<path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16" />
<path d="M8 16H3v5" />
</svg>
20 changes: 20 additions & 0 deletions src/icons/RefreshCWOff.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-refresh-cw-off-icon lucide-refresh-cw-off"
>
<path d="M21 8L18.74 5.74A9.75 9.75 0 0 0 12 3C11 3 10.03 3.16 9.13 3.47" />
<path d="M8 16H3v5" />
<path d="M3 12C3 9.51 4 7.26 5.64 5.64" />
<path d="m3 16 2.26 2.26A9.75 9.75 0 0 0 12 21c2.49 0 4.74-1 6.36-2.64" />
<path d="M21 12c0 1-.16 1.97-.47 2.87" />
<path d="M21 3v5h-5" />
<path d="M22 22 2 2" />
</svg>
18 changes: 18 additions & 0 deletions src/icons/RefreshCWWDot.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-refresh-ccw-dot-icon lucide-refresh-ccw-dot"
>
<path d="M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" />
<path d="M3 3v5h5" />
<path d="M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16" />
<path d="M16 16h5v5" />
<circle cx="12" cy="12" r="1" />
</svg>
33 changes: 29 additions & 4 deletions src/utils/rest-table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,24 +130,49 @@ export class RestItem<T extends object> implements IPromiseLike<RestItem<T>> {
return this.errorReason;
}

async update(data: T, options?: RequestInit): Promise<void> {
async apiCall(url: string, data: object, postUpdate: () => void, options?: RequestInit): Promise<void> {
this.setLoading(true);
if (!options)
options = {
method: "PUT",
method: "POST",
body: JSON.stringify(data),
};
try {
const x = await LOGIN.clientRequest(this.keyUrl(), options);
const x = await LOGIN.clientRequest(url, options);
if (x.status !== 200) throw new Error("Unexpected status code: " + x.status);
this.data = data;
postUpdate();
this.setLoading(false);
} catch (err) {
this.setErrorReason("Failed to update item " + this.key());
this.setLoading(false);
}
}

async patch(data: object, postUpdate: (x: T) => T, options?: RequestInit): Promise<void> {
if (!options)
options = {
method: "PATCH",
body: JSON.stringify(data),
};
this.apiCall(
this.keyUrl(),
data,
() => {
this.data = postUpdate(this.data);
},
options,
);
}

async update(data: T, options?: RequestInit): Promise<void> {
if (!options)
options = {
method: "PUT",
body: JSON.stringify(data),
};
this.patch(data, (_: T) => data, options);
}

async remove(options?: RequestInit): Promise<void> {
this.setLoading(true);
if (!options) options = {method: "DELETE"};
Expand Down
30 changes: 29 additions & 1 deletion src/values.scss
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,34 @@ $icon-highlight: #10b981;
cursor: pointer;
}

@mixin button($highlight, $square: true) {
@include button-reset;

display: block;
font-size: 20px;
font-weight: 400;
line-height: 0;
width: 40px;

@if $square {
aspect-ratio: 1/1;
}

color: $highlight;
}

@mixin button-green($square: true) {
@include button(#10b981, $square);
}

@mixin button-red($square: true) {
@include button(#ef4444, $square);
}

@mixin button-gold($square: true) {
@include button(#ffd700, $square);
}

@mixin button-highlight($highlight, $square: true) {
@include button-reset;

Expand All @@ -50,7 +78,7 @@ $icon-highlight: #10b981;
@include button-highlight(#10b981, $square);
}

@mixin button-red-highlight ($square: true) {
@mixin button-red-highlight($square: true) {
@include button-highlight(#ef4444, $square);
}

Expand Down
Loading