Skip to content
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<script lang="ts">
import { getContext } from 'svelte';

import { page } from '$app/stores';

import Icon from '$lib/holocene/icon/icon.svelte';
import Input from '$lib/holocene/input/input.svelte';
import {
Expand All @@ -20,6 +22,7 @@
import { workflowRoutePattern } from '$lib/utilities/namespace-url-pattern';
import { getFocusedElementId } from '$lib/utilities/query/search-attribute-filter';
import { emptyFilter } from '$lib/utilities/query/to-list-workflow-filters';
import { MAX_QUERY_LENGTH } from '$lib/utilities/request-from-api';

import IsTemporalServerVersionGuard from '../is-temporal-server-version-guard.svelte';

Expand Down Expand Up @@ -55,13 +58,14 @@
);

$: workflowsPage = workflowRoutePattern.match(window?.location?.pathname);
$: query = $page.url.searchParams.get('query');
</script>

<MenuContainer>
<MenuButton
id="search-attribute-filter-button"
controls="search-attribute-menu"
disabled={$activeQueryIndex !== null}
disabled={$activeQueryIndex !== null || query?.length >= MAX_QUERY_LENGTH}
count={$filter.attribute ? 0 : filters.length}
on:click={() => (searchAttributeValue = '')}
class="text-nowrap"
Expand Down
3 changes: 3 additions & 0 deletions src/lib/components/workflow/workflow-advanced-search.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import { searchAttributes } from '$lib/stores/search-attributes';
import { refresh, workflowsQuery } from '$lib/stores/workflows';
import { toListWorkflowFilters } from '$lib/utilities/query/to-list-workflow-filters';
import { MAX_QUERY_LENGTH } from '$lib/utilities/request-from-api';
import { updateQueryParameters } from '$lib/utilities/update-query-parameters';

let manualSearchString = '';
Expand Down Expand Up @@ -78,6 +79,8 @@
clearButtonLabel={translate('common.clear-input-button-label')}
on:clear={handleClearInput}
bind:value={manualSearchString}
maxLength={MAX_QUERY_LENGTH}
hideCount
/>
<Button data-testid="manual-search-button" variant="primary" type="submit">
{translate('common.search')}
Expand Down
64 changes: 26 additions & 38 deletions src/lib/holocene/input/input.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
$: disabled = disabled || copyable;
</script>

<div class={merge('flex flex-col gap-1', className)}>
<div class={merge('group flex flex-col gap-1', className)}>
<Label {required} {label} hidden={labelHidden} for={id} />
<div class="input-group flex">
<slot name="before-input" {disabled} />
Expand Down Expand Up @@ -155,15 +155,6 @@
/>
</div>
{/if}
{#if maxLength && !disabled && !hideCount}
<span class="count">
<span
class:ok={maxLength - value.length > 5}
class:warn={maxLength - value.length <= 5}
class:error={maxLength === value.length}>{value.length}</span
>/{maxLength}
</span>
{/if}
{#if suffix}
<div class="suffix">
{suffix}
Expand All @@ -173,15 +164,32 @@
<slot name="after-input" {disabled} />
</div>

<span
class="hint-text inline-block"
class:invalid={!valid}
class:error
class:hidden={!hintText}
role={error ? 'alert' : null}
<div
class="flex justify-between gap-2"
class:hidden={!hintText && (!maxLength || disabled || hideCount)}
>
{hintText}
</span>
<span
class="hint-text inline-block"
class:invalid={!valid}
class:error
role={error ? 'alert' : null}
>
{hintText}
</span>
{#if maxLength && !disabled && !hideCount}
<span
class="invisible text-right text-sm font-medium tracking-widest group-focus-within:visible"
>
<span
class:text-success={maxLength - value?.length > 5}
class:text-warning={maxLength - value?.length <= 5}
class:text-danger={maxLength === value?.length}
>
{value?.length ?? 0}
</span>/{maxLength}
</span>
{/if}
</div>
</div>

<style lang="postcss">
Expand Down Expand Up @@ -233,26 +241,6 @@
@apply mr-2 flex w-6 cursor-pointer items-center justify-center;
}

.count {
@apply mx-2 hidden text-sm font-medium tracking-widest;

> .ok {
@apply text-success;
}

> .warn {
@apply text-warning;
}

> .error {
@apply text-danger;
}
}

.input:focus ~ .count {
@apply block;
}

.hint-text {
@apply text-xs text-primary;

Expand Down
7 changes: 7 additions & 0 deletions src/lib/utilities/request-from-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ type RequestFromAPIOptions = {
signal?: AbortController['signal'];
};

export const MAX_QUERY_LENGTH = 15000;

export const isTemporalAPIError = (obj: unknown): obj is TemporalAPIError =>
(obj as TemporalAPIError)?.message !== undefined &&
typeof (obj as TemporalAPIError)?.message === 'string';
Expand Down Expand Up @@ -80,6 +82,11 @@ export const requestFromAPI = async <T>(
...nextPageToken,
});
}

const queryString = query.toString();
if (queryString.length >= MAX_QUERY_LENGTH) {
query = new URLSearchParams(queryString.substring(0, MAX_QUERY_LENGTH - 1));
Copy link
Collaborator Author

@laurakwhit laurakwhit Jul 29, 2025

Choose a reason for hiding this comment

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

Not sure if this is really what we want to be doing here. Seems like the API should maybe just return an error instead. Maybe we can add something via middleware? Open to suggestions!

Copy link
Collaborator

Choose a reason for hiding this comment

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

Gah ya this is tricky. I don't think we wanna do this because it will almost certainly still result in an error with hacking off the end of the query. I think the spirit of ticket is to prevent the request from ever being sent.

It's really only going to happen on our workflow list query, so I'd suggest we do the check there (onMount with the query param and when triggering via manual query a la copy/paste most likely) and throw error text on the input and prevent triggering the query

Copy link
Collaborator Author

@laurakwhit laurakwhit Jul 30, 2025

Choose a reason for hiding this comment

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

I think it would also happen for the workflow count query, no? Maybe safest to keep something that checks all the requests 🤔

What do you think about a custom response here. That way the error would show up in the UI like this on the /workflows page and the request wouldn't be sent ⬇️
Screenshot 2025-07-30 at 3 35 44 PM

}
const url = toURL(endpoint, query);

try {
Expand Down
Loading