Skip to content

Commit 36e8e65

Browse files
rmunnmyieye
andauthored
Followup work on Svelte 5 migration - code cleanup and so on (#1652)
* Get rid of recursive updates in run() calls TrainTracks and HgLogView components have slightly tricky logic that the migration tool didn't quite figure out correctly. Pulling the run() call apart into multiple `$derived` sections is much cleaner. * Change `$props()` to const if not bindable * Convert on:change in FilterBar to prop function Also got to simplify a convoluted mess around ViewMode in the default authenticated home page. Now that `$derived` values can be overridden, it turned into a very simple `$derived(cookieVal ?? defaultVal)` line, while still allowing the user to set the value. * Remove most uses of `run()` from svelte/legacy A couple uses of `run()` need something non-trivial done to replace them. In one case we need to write better logic in lexSuperForm: the project code should probably be split into two form entries, one calculated code and one override, and the checkbox when checked smoothly replaces the calculated code field with the override field. In the other case where I kept a `run()` call, we will be able to replace it easily once async deriveds become available in Svelte 5. (They're available now in experimental mode, but it's been less than a week so I want to wait until they settle a bit more). * Remove more `run()` usages * Remove `run()` use in project creation page * Remove a preventDefault use from svelte/legacy * Remove redundant undefineds in props Optional props don't need `| undefined` in their type definition, as it's implied by the `?`. And the assignment via `$props` likewise doesn't need to set a default `undefined` value to optional props. * Remove createEventDispatcher from components * Get rid of `run()` in FilterBar and UserTypeahead Also replaced PlainInput with a DebouncedInput component, so that we can switch PlainInput back to being what it sounds like: a plain input field that doesn't try to do anything clever. * Remove `run()` usage from email tester page Note that this would be better as an async derived once it's available (see discussion #15845 in the Svelte repo for details). Until then, this works well enough. * Make PlainInput plain again * UserTypeahead now uses a PlainInput * Fix infinite effect loop in EditUserAccount Accessing the `$form` in onScoreUpdated was causing Svelte to track the entire form as a dependency of the PasswordStrengthMeter component, causing an infinite effect loop as soon as we updated `$form.score`. Svelte is smart enough not to track dependencies for `$form.foo = bar` but needed to be told not to track the `if ($form)` part. * Fix customCode reactivity * Make code-exists error initially undefined * Remove debouncing prop and refactor DebouncedInput to accept values pushes * Fix code_exists error shown delayed --------- Co-authored-by: Tim Haasdyk <[email protected]>
1 parent ad2319a commit 36e8e65

File tree

151 files changed

+591
-749
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

151 files changed

+591
-749
lines changed

frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
"js-cookie": "^3.0.5",
103103
"just-order-by": "^1.0.0",
104104
"mjml": "^4.15.3",
105+
"runed": "^0.26.0",
105106
"set-cookie-parser": "^2.7.1",
106107
"svelte-exmarkdown": "catalog:",
107108
"svelte-intl-precompile": "^0.12.3",

frontend/pnpm-lock.yaml

Lines changed: 14 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/src/lib/components/Badges/ActionBadge.svelte

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,28 @@
11
<script lang="ts">
22
import type { Snippet } from 'svelte';
33
import { Icon, type IconString } from '$lib/icons';
4-
import { createEventDispatcher } from 'svelte';
54
interface Props {
65
disabled?: boolean;
76
actionIcon: IconString;
87
variant?: 'btn-neutral' | 'btn-primary' | 'btn-secondary';
8+
onAction?: () => void;
99
children?: Snippet;
1010
}
1111
12-
let { disabled = false, actionIcon, variant = 'btn-neutral', children }: Props = $props();
12+
const { disabled = false, actionIcon, variant = 'btn-neutral', onAction, children }: Props = $props();
1313
let iconHoverColor = $derived(variant === 'btn-neutral' ? 'group-hover:bg-base-200' : 'group-hover:bg-neutral/50');
1414
15-
const dispatch = createEventDispatcher<{
16-
action: void;
17-
}>();
18-
19-
function onAction(): void {
20-
if (!disabled) {
21-
dispatch('action');
22-
}
15+
function act(): void {
16+
if (!disabled) onAction?.();
2317
}
2418
2519
let pr = $derived(disabled ? '!pr-0' : '!pr-1');
2620
let br = $derived(disabled ? 'border-r-0' : '');
2721
</script>
2822

2923
<button
30-
onclick={onAction}
31-
onkeypress={onAction}
24+
onclick={act}
25+
onkeypress={act}
3226
class="btn badge {variant} group transition whitespace-nowrap gap-1 {pr} {br}"
3327
class:pointer-events-none={disabled}
3428
>

frontend/src/lib/components/Badges/Badge.svelte

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,13 @@
1515
1616
interface Props {
1717
variant?: BadgeVariant;
18-
icon?: IconString | undefined;
19-
hoverIcon?: IconString | undefined;
18+
icon?: IconString;
19+
hoverIcon?: IconString;
2020
outline?: boolean;
2121
children?: Snippet;
2222
}
2323
24-
let {
25-
variant = 'badge-neutral',
26-
icon = undefined,
27-
hoverIcon = undefined,
28-
outline = false,
29-
children,
30-
}: Props = $props();
24+
const { variant = 'badge-neutral', icon, hoverIcon, outline = false, children }: Props = $props();
3125
</script>
3226

3327
<span

frontend/src/lib/components/Badges/BadgeButton.svelte

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@
44
import Badge from './Badge.svelte';
55
66
// Add more as necessary. Should be as limited as possible to maximize consistency.
7-
type BadgeButtonVariant = 'badge-success' | 'badge-warning' | 'badge-neutral' | undefined;
7+
type BadgeButtonVariant = 'badge-success' | 'badge-warning' | 'badge-neutral';
88
interface Props {
99
variant?: BadgeButtonVariant;
10-
icon?: IconString | undefined;
11-
hoverIcon?: IconString | undefined;
10+
icon?: IconString;
11+
hoverIcon?: IconString;
1212
disabled?: boolean;
1313
onclick?: () => void;
1414
children?: Snippet;
1515
}
1616
17-
let {
17+
const {
1818
variant = undefined,
1919
icon = undefined,
2020
hoverIcon = undefined,

frontend/src/lib/components/Badges/BadgeList.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
children?: Snippet;
66
}
77
8-
let { grid = false, children }: Props = $props();
8+
const { grid = false, children }: Props = $props();
99
</script>
1010

1111
<span class:grid class:inline-flex={!grid} class="badge-list flex-wrap gap-3 justify-items-stretch">

frontend/src/lib/components/Badges/MemberBadge.svelte

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,16 @@
77
interface Props {
88
member: { name: string; role: ProjectRole };
99
canManage?: boolean;
10+
onAction?: () => void;
1011
type?: 'existing' | 'new';
1112
}
1213
13-
let { member, canManage = false, type = 'existing' }: Props = $props();
14-
let actionIcon = ($derived(type === 'existing' ? 'i-mdi-dots-vertical' as const : 'i-mdi-close' as const));
15-
let variant = $derived(member.role === ProjectRole.Manager ? 'btn-primary' as const : 'btn-secondary' as const);
14+
const { member, canManage = false, onAction, type = 'existing' }: Props = $props();
15+
let actionIcon = $derived(type === 'existing' ? ('i-mdi-dots-vertical' as const) : ('i-mdi-close' as const));
16+
let variant = $derived(member.role === ProjectRole.Manager ? ('btn-primary' as const) : ('btn-secondary' as const));
1617
</script>
1718

18-
<ActionBadge {actionIcon} {variant} disabled={!canManage} on:action>
19+
<ActionBadge {actionIcon} {variant} disabled={!canManage} {onAction}>
1920
<span class="pr-3 whitespace-nowrap overflow-ellipsis overflow-x-clip" title={member.name}>
2021
{member.name}
2122
</span>

frontend/src/lib/components/Badges/OrgMemberBadge.svelte

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,16 @@
77
interface Props {
88
member: { name: string; role: OrgRole };
99
canManage?: boolean;
10+
onAction?: () => void;
1011
type?: 'existing' | 'new';
1112
}
1213
13-
let { member, canManage = false, type = 'existing' }: Props = $props();
14-
let actionIcon = ($derived(type === 'existing' ? 'i-mdi-dots-vertical' as const : 'i-mdi-close' as const));
15-
let variant = $derived(member.role === OrgRole.Admin ? 'btn-primary' as const : 'btn-secondary' as const);
14+
const { member, canManage = false, onAction, type = 'existing' }: Props = $props();
15+
let actionIcon = $derived(type === 'existing' ? ('i-mdi-dots-vertical' as const) : ('i-mdi-close' as const));
16+
let variant = $derived(member.role === OrgRole.Admin ? ('btn-primary' as const) : ('btn-secondary' as const));
1617
</script>
1718

18-
<ActionBadge {actionIcon} {variant} disabled={!canManage} on:action>
19+
<ActionBadge {actionIcon} {variant} disabled={!canManage} {onAction}>
1920
<span class="pr-3 whitespace-nowrap overflow-ellipsis overflow-x-clip" title={member.name}>
2021
{member.name}
2122
</span>

frontend/src/lib/components/ButtonToggle.svelte

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
<script lang="ts">
2-
import { preventDefault } from 'svelte/legacy';
3-
42
interface Props {
53
icon1: string;
64
icon2: string;
@@ -9,21 +7,16 @@
97
style: string;
108
}
119
12-
let {
13-
icon1,
14-
icon2,
15-
text1,
16-
text2,
17-
style
18-
}: Props = $props();
10+
const { icon1, icon2, text1, text2, style }: Props = $props();
1911
let isIconOne = $state(true);
2012
21-
function handleClick(): void {
13+
function handleClick(event: Event): void {
2214
isIconOne = !isIconOne;
15+
event.preventDefault();
2316
}
2417
</script>
2518

26-
<button onclick={preventDefault(handleClick)} class="btn {style} flex items-center">
19+
<button onclick={handleClick} class="btn {style} flex items-center">
2720
{#if isIconOne}
2821
<span>{text1} </span>
2922
<span class="{icon1} text-lg"></span>

frontend/src/lib/components/BypassCloudflareEmailObfuscation.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
children?: Snippet;
55
}
66
7-
let { children }: Props = $props();
7+
const { children }: Props = $props();
88
</script>
99

1010
<!--cloudflare replaces email addresses with a hash, however this can mess up the dom and break svelte, so sometimes we need to bypass it-->

0 commit comments

Comments
 (0)