Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Style ESV integration #416

Merged
merged 11 commits into from
Oct 15, 2021
31 changes: 30 additions & 1 deletion gui/src/components/Button.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
<script lang="ts">
import * as router from 'svelte-spa-router';
import { createEventDispatcher } from 'svelte';
import { absoluteUrl } from '../lib/regex';

export let type: string | undefined = undefined;
export let href: string | undefined = undefined;

export let small: boolean = false;

Expand All @@ -8,9 +13,33 @@
export let inset: boolean = false;

export let disabled = false;

const dispatch = createEventDispatcher();

const handleClick = (e: MouseEvent) => {
if (href) {
if (!absoluteUrl.test(href)) {
// Handle internal routes.
router.push(href);
return;
}
// Handle external routes (open in new tab).
window.open(href, '_blank')?.focus();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nbd but I'd prefer if external links were actually anchor tags, styled to look like buttons rather than using JS. That way the user can know what will happen before they click on the link.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted in #417

return;
}
// No-href default handling.
dispatch('click', e);
};
</script>

<button {disabled} class:small class:danger class:inset on:click {type}>
<button
{disabled}
class:small
class:danger
class:inset
on:click|preventDefault={handleClick}
{type}
>
<slot />
</button>

Expand Down
6 changes: 6 additions & 0 deletions gui/src/components/CheckeredTableWrapper.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@
overflow: hidden;
}

div :global(th) {
font-size: 0.85em;
font-weight: 450;
color: var(--grey-5-color);
}

div :global(td),
div :global(th) {
text-align: left;
Expand Down
4 changes: 4 additions & 0 deletions gui/src/components/Icon.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
| 'Home'
| 'Layers'
| 'LeftUp'
| 'Lock'
| 'LogoDeno'
| 'LogoDiscord'
| 'LogoDjango'
Expand Down Expand Up @@ -60,6 +61,7 @@
import HomeGlyph from './icon/glyphs/Home.svelte';
import LayersGlyph from './icon/glyphs/Layers.svelte';
import LeftUpGlyph from './icon/glyphs/LeftUp.svelte';
import LockGlyph from './icon/glyphs/Lock.svelte';
import LogoDenoGlyph from './icon/glyphs/LogoDeno.svelte';
import LogoDiscordGlyph from './icon/glyphs/LogoDiscord.svelte';
import LogoDjangoGlyph from './icon/glyphs/LogoDjango.svelte';
Expand Down Expand Up @@ -117,6 +119,8 @@
<LayersGlyph />
{:else if glyph === 'LeftUp'}
<LeftUpGlyph />
{:else if glyph === 'Lock'}
<LockGlyph />
{:else if glyph === 'LogoDeno'}
<LogoDenoGlyph />
{:else if glyph === 'LogoDiscord'}
Expand Down
3 changes: 2 additions & 1 deletion gui/src/components/Link.svelte
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
<script lang="ts">
import * as router from 'svelte-spa-router';
import { absoluteUrl } from '../lib/regex';

export let href: string;
</script>

<a
{href}
on:click={(event) => {
if (href.startsWith('#')) {
if (!absoluteUrl.test(href)) {
router.push(href);
event.preventDefault();
}
Expand Down
3 changes: 1 addition & 2 deletions gui/src/components/icon/glyphs/Add.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<svg
fill="none"
fill="currentColor"
viewBox="0 0 24 24"
height="24"
width="24"
Expand All @@ -8,6 +8,5 @@
<path
xmlns="http://www.w3.org/2000/svg"
d="M12 4C12.5523 4 13 4.44772 13 5V11H19C19.5523 11 20 11.4477 20 12C20 12.5523 19.5523 13 19 13H13V19C13 19.5523 12.5523 20 12 20C11.4477 20 11 19.5523 11 19V13H5C4.44772 13 4 12.5523 4 12C4 11.4477 4.44772 11 5 11H11V5C11 4.44772 11.4477 4 12 4Z"
fill="#0D0D0D"
/>
</svg>
12 changes: 12 additions & 0 deletions gui/src/components/icon/glyphs/Lock.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<svg
fill="currentColor"
viewBox="0 0 24 24"
height="24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<path
xmlns="http://www.w3.org/2000/svg"
d="M12 4C13.6477 4 15 5.35228 15 7V10H9V7C9 5.35228 10.3523 4 12 4ZM17 10V7C17 4.24772 14.7523 2 12 2C9.24771 2 7 4.24772 7 7V10H6C4.89543 10 4 10.8954 4 12V20C4 21.1046 4.89543 22 6 22H18C19.1046 22 20 21.1046 20 20V12C20 10.8954 19.1046 10 18 10H17ZM6 12H18V20H6V12Z"
/>
</svg>
1 change: 1 addition & 0 deletions gui/src/lib/regex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const absoluteUrl = /^https?:\/\//i;
15 changes: 9 additions & 6 deletions gui/src/pages/WorkspaceAddVault.svelte
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
<script lang="ts">
import * as router from 'svelte-spa-router';
import Panel from '../components/Panel.svelte';
import Icon from '../components/Icon.svelte';
import Layout from '../components/Layout.svelte';
import Textbox from '../components/Textbox.svelte';
import WorkspaceNav from '../components/WorkspaceNav.svelte';
import SubmitButton from '../components/form/SubmitButton.svelte';
import CenterFormPanel from '../components/form/CenterFormPanel.svelte';
import { api } from '../lib/api';

export let params = { workspace: '' };

const workspaceId = params.workspace;
const workspace = api.workspace(workspaceId);
const workspaceRoute = `/workspaces/${encodeURIComponent(workspaceId)}`;
const backRoute = `/workspaces/${encodeURIComponent(workspaceId)}/variables`;

// TODO: inject this.
const esvUrl = 'https://secrets.deref.io/organizations';
Expand All @@ -20,7 +22,8 @@

<Layout>
<WorkspaceNav {workspaceId} active="Variables" slot="navbar" />
<Panel title="Workspace Variables" backRoute={workspaceRoute}>
<CenterFormPanel title="Add Vault" {backRoute}>
<h1><Icon glyph="Lock" /> Add Secrets Vault</h1>
<form
on:submit={async () => {
await workspace.addVault({
Expand All @@ -34,10 +37,10 @@
>
<p>Enter a URL for your vault:</p>
<Textbox bind:value={vaultUrl} --input-width="100%" autofocus />
<button type="submit">Add</button>
<SubmitButton>Add Secrets Vault</SubmitButton>
</form>

<h2>Need a vault?</h2>
<a href={esvUrl}>Create one with Exo Secrets</a>
</Panel>
<a href={esvUrl}>Create one with Exo Secrets Vault</a>
</CenterFormPanel>
</Layout>
96 changes: 51 additions & 45 deletions gui/src/pages/WorkspaceVariables.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<script lang="ts">
import * as router from 'svelte-spa-router';
import Panel from '../components/Panel.svelte';
import Button from '../components/Button.svelte';
import Layout from '../components/Layout.svelte';
Expand Down Expand Up @@ -37,57 +36,64 @@
{#await requests}
<Spinner />
{:then [variables, vaults]}
{#if Object.keys(variables).length === 0}
<div>Empty Environment</div>
<div class="vaults-title">
<h2>Secrets Vaults</h2>
<Button href={`${workspaceRoute}/add-vault`} small>+ Add vault</Button>
</div>
{#if vaults.length > 0}
<CheckeredTableWrapper>
<table>
<thead>
<tr>
<th>Name</th>
<th>URL</th>
<th />
</tr>
</thead>
<tbody>
{#each vaults as vault}
<tr>
<td>{vault.name}</td>
<td>{vault.url}</td>
<td>
{#if vault.connected}
<Button href={`${vault.url}/create-secret`} small>
+ New secret
</Button>
{:else if vault.needsAuth}
<Button on:click={authEsv} small>Authenticate</Button>
{:else}
Bad vault URL
{/if}
</td>
</tr>
{/each}
</tbody>
</table>
</CheckeredTableWrapper>
{:else}
<div>No vaults linked to this workspace.</div>
{/if}
{#if Object.keys(variables).length > 0}
<hr />
<h2>Variables</h2>
<EnvironmentTable {variables} />
{:else}
<div>Empty environment, no variables found.</div>
{/if}
<h2>Vaults</h2>
<CheckeredTableWrapper>
<table>
<thead>
<tr>
<th>Name</th>
<th>URL</th>
<th />
</tr>
</thead>
<tbody>
{#each vaults as vault}
<tr>
<td>{vault.name}</td>
<td>{vault.url}</td>
<td>
{#if vault.connected}
<a href={`${vault.url}/create-secret`} target="_blank"
>Create secret</a
>
{:else if vault.needsAuth}
<Button on:click={authEsv}>Authenticate</Button>
{:else}
Bad vault URL
{/if}
</td>
</tr>
{/each}
<tr>
<td colspan="3">
<Button
on:click={() => router.push(`${workspaceRoute}/add-vault`)}
>
Add vault
</Button>
</td>
</tr>
</tbody>
</table>
</CheckeredTableWrapper>
{/await}
</Panel>
</Layout>

<style>
h2 {
margin-top: 1.5em;
.vaults-title {
display: flex;
align-items: center;
gap: 18px;
margin-bottom: 24px;
}

.vaults-title h2 {
margin: 0;
}
</style>