Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion server/config/docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ codec:
includeCredentials: {{ env "TEMPORAL_CODEC_INCLUDE_CREDENTIALS" | default "false" }}
defaultErrorMessage: {{ env "TEMPORAL_CODEC_DEFAULT_ERROR_MESSAGE" | default "" }}
defaultErrorLink: {{ env "TEMPORAL_CODEC_DEFAULT_ERROR_LINK" | default "" }}

environment:
name: {{ env "TEMPORAL_ENVIRONMENT_NAME" | default "" }}
forwardHeaders:
{{- if env "TEMPORAL_FORWARD_HEADERS" }}
{{- range env "TEMPORAL_FORWARD_HEADERS" | split "," }}
Expand Down
8 changes: 8 additions & 0 deletions server/server/api/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ type CodecResponse struct {
DefaultErrorLink string
}

type Environment struct {
Name string
}

type SettingsResponse struct {
Auth *Auth
BannerText string
Expand All @@ -65,6 +69,7 @@ type SettingsResponse struct {
FeedbackURL string
NotifyOnNewVersion bool
Codec *CodecResponse
Environment *Environment
Version string
DisableWriteActions bool
WorkflowTerminateDisabled bool
Expand Down Expand Up @@ -143,6 +148,9 @@ func GetSettings(cfgProvider *config.ConfigProviderWithRefresh) func(echo.Contex
DefaultErrorMessage: cfg.Codec.DefaultErrorMessage,
DefaultErrorLink: cfg.Codec.DefaultErrorLink,
},
Environment: &Environment{
Name: cfg.Environment.Name,
},
Version: version.UIVersion,
DisableWriteActions: cfg.DisableWriteActions,
WorkflowTerminateDisabled: cfg.WorkflowTerminateDisabled,
Expand Down
5 changes: 5 additions & 0 deletions server/server/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type (
// How often to reload the config
RefreshInterval time.Duration `yaml:"refreshInterval"`
Codec Codec `yaml:"codec"`
Environment Environment `yaml:"environment"`
DisableWriteActions bool `yaml:"disableWriteActions"`
// Discrete configuration for Workflow Actions in the UI
WorkflowTerminateDisabled bool `yaml:"workflowTerminateDisabled"`
Expand Down Expand Up @@ -136,6 +137,10 @@ type (
DefaultErrorLink string `yaml:"defaultErrorLink"`
}

Environment struct {
Name string `yaml:"name"`
}

Filesystem struct {
Path string `yaml:"path"`
}
Expand Down
77 changes: 49 additions & 28 deletions src/lib/components/bottom-nav.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
import { writable } from 'svelte/store';
import { slide } from 'svelte/transition';

import type { Snippet } from 'svelte';
import { twMerge as merge } from 'tailwind-merge';

import { beforeNavigate } from '$app/navigation';
import { page } from '$app/stores';
import { page } from '$app/state';

import Button from '$lib/holocene/button.svelte';
import Icon from '$lib/holocene/icon/icon.svelte';
Expand All @@ -14,20 +15,35 @@
import { lastUsedNamespace } from '$lib/stores/namespaces';
import type { NamespaceListItem, NavLinkListItem } from '$lib/types/global';
import { routeForNamespace } from '$lib/utilities/route-for';
import ziggy from '$lib/vendor/ziggy-full-face.png';

import BottomNavLinks from './bottom-nav-links.svelte';
import BottomNavNamespaces from './bottom-nav-namespaces.svelte';
import BottomNavSettings from './bottom-nav-settings.svelte';

export let namespaceList: NamespaceListItem[] | undefined = [];
export let linkList: NavLinkListItem[];
export let isCloud = false;
export let showNamespacePicker = true;
type Props = {
children: Snippet;
namespacePicker: Snippet<[{ open: boolean; closeMenu: () => void }]>;
avatar: Snippet;
namespaceList?: NamespaceListItem[];
isCloud: boolean;
linkList: NavLinkListItem[];
showNamespacePicker?: boolean;
environmentName?: string;
};

let viewLinks = false;
let {
children,
namespacePicker,
avatar,
namespaceList = [],
isCloud = false,
linkList,
showNamespacePicker = true,
environmentName,
}: Props = $props();

let viewLinks = $state(false);
let viewNamespaces = writable(false);
let viewSettings = false;
let viewSettings = $state(false);

function escapeHandler(e: KeyboardEvent) {
if (
Expand All @@ -42,10 +58,13 @@
closeMenu();
});

$: namespace = $page.params.namespace || $lastUsedNamespace;
$: namespaceExists = namespaceList.some(
(namespaceListItem) => namespaceListItem.namespace === namespace,
const namespace = $derived(page.params.namespace || $lastUsedNamespace);
const namespaceExists = $derived(
namespaceList.some(
(namespaceListItem) => namespaceListItem.namespace === namespace,
),
);
const menuIsOpen = $derived(viewLinks || $viewNamespaces || viewSettings);

const onLinksClick = () => {
viewLinks = !viewLinks;
Expand All @@ -71,8 +90,6 @@
viewSettings = false;
}

$: menuIsOpen = viewLinks || $viewNamespaces || viewSettings;

const truncateNamespace = (namespace: string) => {
if (namespace.length > 16) {
return `${namespace.slice(0, 8)}...${namespace.slice(-8)}`;
Expand All @@ -97,11 +114,9 @@
out:slide={{ duration: 200, delay: 0 }}
>
<BottomNavLinks open={viewLinks} {linkList} />
<slot name="nsPicker" open={$viewNamespaces} {closeMenu}>
<BottomNavNamespaces open={$viewNamespaces} {namespaceList} />
</slot>
{@render namespacePicker({ open: $viewNamespaces, closeMenu })}
<BottomNavSettings open={viewSettings}>
<slot />
{@render children?.()}
</BottomNavSettings>
</div>
{/if}
Expand All @@ -111,7 +126,7 @@
'focus-visible:[&_a]:outline-none focus-visible:[&_a]:ring-2 focus-visible:[&_a]:ring-primary/70 focus-visible:[&_button]:outline-none focus-visible:[&_button]:ring-2 focus-visible:[&_button]:ring-primary/70',
isCloud
? 'bg-gradient-to-b from-indigo-600 to-indigo-900 text-off-white focus-visible:[&_a]:ring-success focus-visible:[&_button]:ring-success'
: 'surface-black border-t border-subtle',
: environmentName || 'surface-black border-t border-subtle',
)}
data-testid="top-nav"
aria-label={translate('common.main')}
Expand All @@ -121,7 +136,7 @@
data-testid="nav-menu-button"
class:active-shadow={viewLinks}
type="button"
on:click={onLinksClick}
onclick={onLinksClick}
>
{#if viewLinks}
<Icon name="close" height={32} width={32} />
Expand Down Expand Up @@ -154,21 +169,15 @@
data-testid="nav-profile-button"
class:active-shadow={viewSettings}
type="button"
on:click={onSettingsClick}
onclick={onSettingsClick}
>
{#if viewSettings}
<Icon name="close" height={32} width={32} />
{:else}
<div
class="flex aspect-square w-[32px] min-w-[32px] items-center justify-center"
>
<slot name="profile-picture">
<img
src={ziggy}
alt={translate('common.user-profile')}
class="h-[32px] w-[32px]"
/>
</slot>
{@render avatar()}
</div>
{/if}
</button>
Expand All @@ -182,4 +191,16 @@
.nav-button {
@apply relative select-none p-1 text-center align-middle text-xs font-medium uppercase transition-all;
}

.development {
@apply surface-development border-t border-subtle;
}

.staging {
@apply surface-staging border-t border-subtle;
}

.test {
@apply surface-test border-t border-subtle;
}
</style>
28 changes: 22 additions & 6 deletions src/lib/components/side-nav.svelte
Original file line number Diff line number Diff line change
@@ -1,14 +1,30 @@
<script lang="ts">
import type { Snippet } from 'svelte';

import Navigation from '$lib/holocene/navigation/navigation-container.svelte';
import NavigationItem from '$lib/holocene/navigation/navigation-item.svelte';
import { translate } from '$lib/i18n/translate';
import type { NavLinkListItem } from '$lib/types/global';

export let isCloud = false;
export let linkList: NavLinkListItem[];
type Props = {
isCloud: boolean;
linkList: NavLinkListItem[];
environmentName?: string;
bottomActions?: Snippet;
};
let {
isCloud = false,
linkList,
environmentName,
bottomActions,
}: Props = $props();
</script>

<Navigation {isCloud} aria-label={translate('common.primary')}>
<Navigation
{isCloud}
{environmentName}
aria-label={translate('common.primary')}
>
{#each linkList as item}
{#if !item?.hidden}
{#if item.divider}
Expand All @@ -25,7 +41,7 @@
/>
{/if}
{/each}
<svelte:fragment slot="bottom">
<slot name="bottom" />
</svelte:fragment>
{#snippet bottom()}
{@render bottomActions?.()}
{/snippet}
</Navigation>
17 changes: 14 additions & 3 deletions src/lib/holocene/main-content-container.svelte
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
<script lang="ts">
import type { Snippet } from 'svelte';

type Props = {
children: Snippet;
main: Snippet;
footer: Snippet;
};
let { children, main, footer }: Props = $props();
</script>

<div
id="content-wrapper"
class="relative h-screen w-max flex-auto overflow-auto"
>
<slot />
{@render children()}
<main id="content" class="pb-16 md:pb-0">
<slot name="main" />
{@render main()}
</main>
<slot name="footer" />
{@render footer()}
</div>
55 changes: 44 additions & 11 deletions src/lib/holocene/navigation/navigation-container.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';

import type { Snippet } from 'svelte';
import { twMerge as merge } from 'tailwind-merge';

import { resolve } from '$app/paths';
Expand All @@ -12,14 +13,25 @@
import { navOpen } from '$lib/stores/nav-open';

interface Props extends HTMLAttributes<HTMLDivElement> {
isCloud?: boolean;
isCloud: boolean;
environmentName?: string;
children?: Snippet;
bottom?: Snippet;
}

let { isCloud = false, ...restProps }: Props = $props();
let {
isCloud = false,
environmentName = '',
children,
bottom,
...restProps
}: Props = $props();

const toggle = () => ($navOpen = !$navOpen);

let version = $derived(page.data?.settings?.version ?? '');
const version = $derived(page.data?.settings?.version ?? '');
const showEnvironmentName = $derived(
!isCloud && environmentName && environmentName.trim().length > 0,
);
</script>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

  • ⚠️ Argument of type '{ accesskey?: string | null | undefined; autocapitalize?: "on" | "off" | "none" | "characters" | "sentences" | "words" | null | undefined; autofocus?: boolean | null | undefined; class: ClassValue | null; ... 426 more ...; onfullscreenerrorcapture?: EventHandler<...> | ... 1 more ... | undefined; }' is not assignable to parameter of type 'HTMLProps<"nav", HTMLAttributes>'.

<nav
Expand All @@ -28,7 +40,7 @@
'focus-visible:[&_[role=button]]:outline-none focus-visible:[&_[role=button]]:ring-2 focus-visible:[&_[role=button]]:ring-primary/70 focus-visible:[&_a]:outline-none focus-visible:[&_a]:ring-2 focus-visible:[&_a]:ring-primary/70',
isCloud
? 'bg-gradient-to-b from-indigo-600 to-indigo-950 text-off-white focus-visible:[&_[role=button]]:outline-none focus-visible:[&_[role=button]]:ring-2 focus-visible:[&_[role=button]]:ring-success focus-visible:[&_a]:ring-success'
: 'surface-black',
: environmentName || 'surface-black',
)}
data-nav={$navOpen ? 'open' : 'closed'}
data-testid="navigation-header"
Expand All @@ -39,9 +51,16 @@
>
<a href={resolve('', {})} class="flex w-fit items-center gap-1 text-nowrap">
<Logo height={24} width={24} class="m-1" />
<p class="text-base font-medium group-data-[nav=closed]:hidden">
{isCloud ? 'Cloud' : 'Self-Hosted'}
</p>
<div>
<p class="text-base font-medium group-data-[nav=closed]:hidden">
{isCloud ? 'Cloud' : 'Self-Hosted'}
</p>
{#if showEnvironmentName}
<p class="font-mono text-xs group-data-[nav=closed]:hidden">
{environmentName.toUpperCase()}
</p>
{/if}
</div>
</a>
<button
title={$navOpen ? 'Collapse Navigation' : 'Expand Navigation'}
Expand All @@ -54,15 +73,29 @@
</button>
</div>
<div role="list">
<slot />
{@render children?.()}
</div>
<div class="self-end">
<slot name="bottom" />
{@render bottom?.()}
<div
class="self-center justify-self-center py-3 text-center text-[0.6rem] text-slate-300"
class="self-center justify-self-center py-3 text-center text-[0.6rem] text-slate-100"
>
<span class="sr-only">{translate('common.version')}</span>
{version}
</div>
</div>
</nav>

<style lang="postcss">
.development {
@apply surface-development;
}

.staging {
@apply surface-staging;
}

.test {
@apply surface-test;
}
</style>
3 changes: 3 additions & 0 deletions src/lib/services/settings-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ export const fetchSettings = async (request = fetch): Promise<Settings> => {
},
defaultNamespace: settingsResponse?.DefaultNamespace || 'default', // API returns an empty string if default namespace is not configured
disableWriteActions: !!settingsResponse?.DisableWriteActions || false,
buildEnvironment: {
name: settingsResponse?.Environment?.Name || '',
},
workflowTerminateDisabled: !!settingsResponse?.WorkflowTerminateDisabled,
workflowCancelDisabled: !!settingsResponse?.WorkflowCancelDisabled,
workflowSignalDisabled: !!settingsResponse?.WorkflowSignalDisabled,
Expand Down
Loading
Loading