feat: offer a demo instance link from the live deployment
This commit is contained in:
parent
cdace7d170
commit
b60a492417
10 changed files with 63 additions and 8 deletions
|
|
@ -8,6 +8,7 @@ const props = defineProps<{
|
|||
auth: AuthState
|
||||
mode: AppMode | null
|
||||
healthFailed: boolean
|
||||
demoUrl: string | null
|
||||
}>()
|
||||
const emit = defineEmits<{ logout: []; reset: []; toggleDev: [opener: HTMLElement] }>()
|
||||
|
||||
|
|
@ -47,6 +48,9 @@ const modeLabel = computed(() => {
|
|||
<span class="mode" :class="{ failed: healthFailed }">
|
||||
{{ modeLabel }}
|
||||
</span>
|
||||
<a v-if="demoUrl" class="demo-link" :href="demoUrl">
|
||||
{{ messages.appHeaderDemoInstance }}
|
||||
</a>
|
||||
<AuthStatus :auth="auth" @logout="$emit('logout')" />
|
||||
<button class="button" type="button" data-dev-panel-opener @click="openDevPanel">
|
||||
<span class="full-label">
|
||||
|
|
@ -141,6 +145,18 @@ const modeLabel = computed(() => {
|
|||
color: var(--c-error);
|
||||
}
|
||||
|
||||
.demo-link {
|
||||
color: var(--c-text-chip);
|
||||
text-transform: uppercase;
|
||||
text-decoration: none;
|
||||
border-bottom: 1px solid var(--c-line-strong);
|
||||
}
|
||||
|
||||
.demo-link:hover {
|
||||
color: var(--c-text);
|
||||
border-color: var(--c-accent);
|
||||
}
|
||||
|
||||
.button {
|
||||
min-height: 31px;
|
||||
padding: 6px 11px;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import StreamError from './StreamError.vue'
|
|||
import StreamWarning from './StreamWarning.vue'
|
||||
import ThinkingIndicator from './ThinkingIndicator.vue'
|
||||
|
||||
const props = defineProps<{ turn: AssistantTurn; canSave: boolean }>()
|
||||
const props = defineProps<{ turn: AssistantTurn; canSave: boolean; demoUrl: string | null }>()
|
||||
defineEmits<{ save: []; retry: [query: string] }>()
|
||||
|
||||
const thinkingLabel = computed(() => {
|
||||
|
|
@ -54,12 +54,14 @@ const isEmptyResult = computed(
|
|||
v-if="turn.error"
|
||||
:code="turn.error.code"
|
||||
:message="turn.error.message"
|
||||
:demo-url="demoUrl"
|
||||
@retry="$emit('retry', turn.query)"
|
||||
/>
|
||||
<StreamError
|
||||
v-else-if="turn.transportFailure"
|
||||
:code="turn.transportFailure.kind"
|
||||
:message="turn.transportFailure.message"
|
||||
:demo-url="demoUrl"
|
||||
@retry="$emit('retry', turn.query)"
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ onUnmounted(() => window.removeEventListener('keydown', onShortcut))
|
|||
:auth="auth"
|
||||
:mode="mode"
|
||||
:health-failed="health.status === 'failed'"
|
||||
:demo-url="health.demoUrl"
|
||||
@logout="logout"
|
||||
@reset="reset"
|
||||
@toggle-dev="openDevPanel"
|
||||
|
|
@ -122,6 +123,7 @@ onUnmounted(() => window.removeEventListener('keydown', onShortcut))
|
|||
:turns="turns"
|
||||
:suggestions="DISCOVERY_SUGGESTIONS"
|
||||
:can-save="canSave"
|
||||
:demo-url="health.demoUrl"
|
||||
@pick="pickSuggestion"
|
||||
@save="savePlaylist"
|
||||
@retry="retryQuery"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ const props = defineProps<{
|
|||
turns: ChatTurn[]
|
||||
suggestions: readonly string[]
|
||||
canSave: boolean
|
||||
demoUrl: string | null
|
||||
}>()
|
||||
defineEmits<{
|
||||
pick: [suggestion: string]
|
||||
|
|
@ -107,6 +108,7 @@ watch(streaming, (value) => {
|
|||
v-else
|
||||
:turn="turn"
|
||||
:can-save="canSave"
|
||||
:demo-url="demoUrl"
|
||||
@save="$emit('save', turn.id)"
|
||||
@retry="$emit('retry', $event)"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import { messages } from '../lib/messages'
|
||||
|
||||
defineProps<{ code: string; message: string }>()
|
||||
defineProps<{ code: string; message: string; demoUrl?: string | null }>()
|
||||
defineEmits<{ retry: [] }>()
|
||||
</script>
|
||||
|
||||
|
|
@ -9,6 +9,9 @@ defineEmits<{ retry: [] }>()
|
|||
<div class="error" role="alert" :data-error-code="code">
|
||||
<p>{{ message }}</p>
|
||||
<button type="button" @click="$emit('retry')">{{ messages.streamErrorRetry }}</button>
|
||||
<a v-if="demoUrl" class="demo-link" :href="demoUrl">
|
||||
{{ messages.streamErrorDemoInstance }}
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -36,4 +39,16 @@ defineEmits<{ retry: [] }>()
|
|||
border-radius: var(--r-md);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.demo-link {
|
||||
display: inline-block;
|
||||
margin-top: var(--s-3);
|
||||
margin-left: var(--s-3);
|
||||
padding: 8px var(--s-4);
|
||||
color: var(--c-text);
|
||||
font-family: var(--f-mono);
|
||||
font-size: var(--t-micro);
|
||||
border: 1px solid var(--c-line-strong);
|
||||
border-radius: var(--r-md);
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -35,7 +35,12 @@ function loginFailed(): boolean {
|
|||
/** Manage authentication, service mode, and playlist API operations. */
|
||||
export function useApi() {
|
||||
const auth = ref<AuthState>({ status: 'checking', user: null, message: null })
|
||||
const health = ref<HealthState>({ status: 'checking', mode: null, message: null })
|
||||
const health = ref<HealthState>({
|
||||
status: 'checking',
|
||||
mode: null,
|
||||
message: null,
|
||||
demoUrl: null,
|
||||
})
|
||||
|
||||
async function loadAuth(hadLoginError: boolean): Promise<void> {
|
||||
try {
|
||||
|
|
@ -81,12 +86,17 @@ export function useApi() {
|
|||
) {
|
||||
throw new Error(messages.useApiInvalidHealth)
|
||||
}
|
||||
health.value = { status: 'ready', mode: body.mode, message: null }
|
||||
const demoUrl =
|
||||
typeof body.demo_url === 'string' && body.demo_url.startsWith('https://')
|
||||
? body.demo_url
|
||||
: null
|
||||
health.value = { status: 'ready', mode: body.mode, message: null, demoUrl }
|
||||
} catch {
|
||||
health.value = {
|
||||
status: 'failed',
|
||||
mode: null,
|
||||
message: messages.useApiModeUnavailable,
|
||||
demoUrl: null,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
export const messages = {
|
||||
appHeaderBrandPrefix: 'discovery',
|
||||
appHeaderBrandResetLabel: 'discovery-by-llm: start a new chat',
|
||||
appHeaderDemoInstance: 'demo',
|
||||
appHeaderBrandAccent: '-by-',
|
||||
appHeaderBrandSuffix: 'llm',
|
||||
appHeaderKicker: 'proof of concept',
|
||||
|
|
@ -94,6 +95,7 @@ export const messages = {
|
|||
resultSetRecommendedTrackLabel: '{count} recommended track',
|
||||
resultSetRecommendedTracksLabel: '{count} recommended tracks',
|
||||
|
||||
streamErrorDemoInstance: 'Open the demo instance',
|
||||
streamErrorRetry: 'Edit and retry',
|
||||
|
||||
suggestionChipsRegionLabel: 'Listening suggestions',
|
||||
|
|
|
|||
|
|
@ -49,9 +49,9 @@ export type AuthState =
|
|||
| { status: 'failed'; user: null; message: string }
|
||||
|
||||
export type HealthState =
|
||||
| { status: 'checking'; mode: null; message: null }
|
||||
| { status: 'ready'; mode: AppMode; message: null }
|
||||
| { status: 'failed'; mode: null; message: string }
|
||||
| { status: 'checking'; mode: null; message: null; demoUrl: null }
|
||||
| { status: 'ready'; mode: AppMode; message: null; demoUrl: string | null }
|
||||
| { status: 'failed'; mode: null; message: string; demoUrl: null }
|
||||
|
||||
export interface EventLogEntry {
|
||||
timestamp: string
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue