Skip to content

Commit 7571b84

Browse files
fix: table-state-management add isSaving state to TableStateValues and update UI components to disable interactions during save operations
1 parent 71d0d57 commit 7571b84

File tree

8 files changed

+52
-10
lines changed

8 files changed

+52
-10
lines changed

src/codeblocks/TableWidget.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export class TableWidget extends WidgetType {
3232
const tableStateStore = writable<TableStateValues>({
3333
selectedRowId: null,
3434
isEditing: false,
35+
isSaving: false,
3536
});
3637

3738
return [tableStore, tableStateStore];

src/codeblocks/models/TableStateStore.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { Writable } from 'svelte/store';
33
export type TableStateValues = {
44
selectedRowId: string | null;
55
isEditing: boolean;
6+
isSaving: boolean;
67
};
78

89
export type TableStateStore = Writable<TableStateValues>;

src/codeblocks/models/UiState.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export type UiState = {
22
selectedRowId: string | null;
33
isEditing: boolean;
4+
isSaving: boolean;
45
};

src/codeblocks/ui/componets/Table/AddRow/AddRow.svelte

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44
type Props = {
55
text: string;
66
onClick: () => void;
7+
disabled?: boolean;
78
};
89
9-
const { text, onClick }: Props = $props();
10+
const { text, onClick, disabled = false }: Props = $props();
1011
</script>
1112

12-
<tr class="add-row">
13-
<td colspan="4" onclick={onClick}>
13+
<tr class="add-row" class:disabled={disabled}>
14+
<td colspan="4" onclick={() => (disabled ? undefined : onClick())}>
1415
<div class="button">
1516
<Icon name="circle-plus" />
1617
<span>{text}</span>
@@ -27,6 +28,14 @@
2728
background-color: var(--table-header-background-hover);
2829
}
2930
31+
.add-row.disabled,
32+
.add-row.disabled:hover {
33+
pointer-events: none;
34+
opacity: 0.6;
35+
cursor: not-allowed;
36+
background: inherit;
37+
}
38+
3039
.button {
3140
display: flex;
3241
align-items: center;

src/codeblocks/ui/componets/Table/CategoryRow/CategoryRow.svelte

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
import { Menu } from 'obsidian';
33
import { getContext } from 'svelte';
44
5-
import type { CategoryId } from '../../../../models';
5+
import type { CategoryId, TableStateStore } from '../../../../models';
66
import type { StoreActions } from '../actions';
7-
import { STORE_ACTIONS_CONTEXT_KEY } from '../constants';
7+
import { STORE_ACTIONS_CONTEXT_KEY, STORE_STATE_CONTEXT_KEY } from '../constants';
88
99
import Editable from '../Editable/Editable.svelte';
1010
@@ -17,6 +17,7 @@
1717
const { categoryId, categoryName, isDeletingEnabled }: Props = $props();
1818
let name = $state(categoryName);
1919
20+
const tableState = getContext<TableStateStore>(STORE_STATE_CONTEXT_KEY);
2021
const { newCategory, deleteCategory, selectRow, updateCategory, toggleEditing } =
2122
getContext<StoreActions>(STORE_ACTIONS_CONTEXT_KEY);
2223
@@ -55,7 +56,12 @@
5556

5657
<tr class="category" oncontextmenu={handleOnMenu}>
5758
<td colspan={4} class="cell">
58-
<Editable value={name} onChange={handleOnChange} onEditingChange={toggleEditing} />
59+
<Editable
60+
value={name}
61+
onChange={handleOnChange}
62+
onEditingChange={toggleEditing}
63+
disabled={$tableState.isSaving}
64+
/>
5965
</td>
6066
</tr>
6167

src/codeblocks/ui/componets/Table/Editable/Editable.svelte

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
value: string | number;
66
onChange: (value: string | number) => void;
77
onEditingChange: (isEditing: boolean) => void;
8+
disabled?: boolean;
89
};
910
10-
let { value, onChange, onEditingChange }: Props = $props();
11+
let { value, onChange, onEditingChange, disabled = false }: Props = $props();
1112
1213
const valueType = $derived(typeof value === 'number' ? 'number' : 'text');
1314
const valueDisplay = $derived(
@@ -19,11 +20,13 @@
1920
let inputElement: HTMLInputElement | null = $state(null);
2021
2122
const handleOnClick = (): void => {
23+
if (disabled) return;
2224
isEditing = true;
2325
onEditingChange(true);
2426
};
2527
2628
const handleOnKeyDown = (event: KeyboardEvent): void => {
29+
if (disabled) return;
2730
if (event.key === 'Enter') {
2831
isEditing = true;
2932
onEditingChange(true);
@@ -71,6 +74,7 @@
7174
type={valueType}
7275
min={valueType === 'number' ? '0' : undefined}
7376
step={valueType === 'number' ? '0.10' : undefined}
77+
disabled={disabled}
7478
onblur={handleOnLeave}
7579
onwheel={handleOnWheel}
7680
onkeydown={handleOnInputKeyDown}
@@ -81,6 +85,7 @@
8185
class="text"
8286
class:end={valueType === 'number'}
8387
role="button"
88+
aria-disabled={disabled}
8489
onclick={handleOnClick}
8590
onkeydown={handleOnKeyDown}
8691
>
@@ -127,9 +132,15 @@
127132
display: flex;
128133
align-items: center;
129134
height: var(--input-height);
135+
cursor: text;
130136
}
131137
132138
.end {
133139
justify-content: end;
134140
}
141+
142+
.text[aria-disabled='true'] {
143+
cursor: not-allowed;
144+
opacity: 0.7;
145+
}
135146
</style>

src/codeblocks/ui/componets/Table/Row/Row.svelte

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,12 @@
6565
};
6666
6767
export const handleOnRowClick = (): void => {
68+
if ($tableState.isSaving) return;
6869
selectRow(null);
6970
};
7071
7172
export const handleOnCheckboxClick = (): void => {
73+
if ($tableState.isSaving) return;
7274
selectRow(null);
7375
checked = !checked;
7476
};
@@ -93,6 +95,7 @@
9395
name="checkbox"
9496
id={`checkbox-${row.id}`}
9597
checked={row.checked}
98+
disabled={$tableState.isSaving}
9699
onchange={(value: Event) => {
97100
checked = (value.target as HTMLInputElement).checked;
98101
}}
@@ -105,6 +108,7 @@
105108
value={row.name}
106109
onChange={(value) => (name = String(value))}
107110
onEditingChange={toggleEditing}
111+
disabled={$tableState.isSaving}
108112
/>
109113
</td>
110114

@@ -113,6 +117,7 @@
113117
value={row.amount}
114118
onChange={(value) => (amount = Number(value))}
115119
onEditingChange={toggleEditing}
120+
disabled={$tableState.isSaving}
116121
/>
117122
</td>
118123

@@ -121,6 +126,7 @@
121126
value={row.comment}
122127
onChange={(value) => (comment = String(value))}
123128
onEditingChange={toggleEditing}
129+
disabled={$tableState.isSaving}
124130
/>
125131
</td>
126132
</tr>

src/codeblocks/ui/componets/Table/Table.svelte

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,15 @@
3030
3131
const commitTableChange = debounce(
3232
(categories: TableCategories, rows: TableRows) => {
33-
if (!$tableStateStore.isEditing) {
33+
if ($tableStateStore.isEditing) return;
34+
35+
// Block interactions while saving
36+
tableStateStore.update((s) => ({ ...s, isSaving: true }));
37+
try {
3438
onTableChange(categories, rows);
39+
} finally {
40+
// Release saving lock on next tick to allow CM dispatch to finish
41+
setTimeout(() => tableStateStore.update((s) => ({ ...s, isSaving: false })), 0);
3542
}
3643
},
3744
300,
@@ -76,15 +83,15 @@
7683
<Row {row} />
7784
{/each}
7885

79-
<AddRow text="New Row" onClick={() => newRow(categoryId)} />
86+
<AddRow text="New Row" onClick={() => newRow(categoryId)} disabled={$tableStateStore.isSaving} />
8087

8188
{#if $tableStore.categories.size > 1}
8289
<CategoryFooter {categoryId} />
8390
{/if}
8491
{/each}
8592
</tbody>
8693

87-
<AddRow text="New Category" onClick={newCategory} />
94+
<AddRow text="New Category" onClick={newCategory} disabled={$tableStateStore.isSaving} />
8895

8996
<Footer />
9097
</table>

0 commit comments

Comments
 (0)