Skip to content

Commit 922c268

Browse files
committed
fix: use makeObservable, remove decorators
1 parent d543a8a commit 922c268

11 files changed

Lines changed: 89 additions & 353 deletions

File tree

ui/package.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,7 @@
4646
"testformat": "prettier \"src/**/*.{ts,tsx}\" --list-different"
4747
},
4848
"devDependencies": {
49-
"@babel/core": "^7.29.0",
50-
"@babel/plugin-proposal-decorators": "^7.29.0",
5149
"@eslint/js": "^10.0.0",
52-
"@rolldown/plugin-babel": "^0.2.2",
5350
"@types/node": "^25.9.3",
5451
"@types/notifyjs": "^3.0.5",
5552
"@types/react": "^19.1.9",

ui/src/CurrentUser.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,32 @@ import axios, {AxiosError, AxiosResponse} from 'axios';
22
import * as config from './config';
33
import {detect} from 'detect-browser';
44
import {SnackReporter} from './snack/SnackManager';
5-
import {observable, runInAction, action} from 'mobx';
5+
import {makeObservable, observable, runInAction, action} from 'mobx';
66
import {ICurrentUser} from './types';
77

88
export class CurrentUser {
99
private reconnectTimeoutId: number | null = null;
1010
private reconnectTime = 7500;
11-
@observable accessor loggedIn = false;
12-
@observable accessor refreshKey = 0;
13-
@observable accessor authenticating = true;
14-
@observable accessor user: ICurrentUser = {
11+
public loggedIn = false;
12+
public refreshKey = 0;
13+
public authenticating = true;
14+
public user: ICurrentUser = {
1515
name: 'unknown',
1616
admin: false,
1717
id: -1,
1818
createdAt: '',
1919
};
20-
@observable accessor connectionErrorMessage: string | null = null;
20+
public connectionErrorMessage: string | null = null;
2121

22-
public constructor(private readonly snack: SnackReporter) {}
22+
public constructor(private readonly snack: SnackReporter) {
23+
makeObservable(this, {
24+
loggedIn: observable,
25+
refreshKey: observable,
26+
authenticating: observable,
27+
user: observable,
28+
connectionErrorMessage: observable,
29+
});
30+
}
2331

2432
public register = async (name: string, pass: string): Promise<boolean> =>
2533
axios

ui/src/ElevateStore.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
11
import axios from 'axios';
2-
import {action, observable, runInAction} from 'mobx';
2+
import {action, makeObservable, observable, runInAction} from 'mobx';
33
import * as config from './config';
44
import {SnackReporter} from './snack/SnackManager';
55
import {CurrentUser} from './CurrentUser';
66

77
export class ElevateStore {
8-
@observable accessor elevated = false;
9-
@observable accessor oidcElevatePending = false;
8+
public elevated = false;
9+
public oidcElevatePending = false;
1010
private oidcPollIntervalId: number | undefined = undefined;
1111
private oidcPopup: Window | null = null;
1212

1313
public constructor(
1414
private readonly snack: SnackReporter,
1515
private readonly currentUser: CurrentUser
16-
) {}
16+
) {
17+
makeObservable(this, {
18+
elevated: observable,
19+
oidcElevatePending: observable,
20+
refreshElevated: action,
21+
});
22+
}
1723

18-
@action
1924
public refreshElevated = (): number => {
2025
const elevatedUntil = this.currentUser.user.elevatedUntil;
2126
if (!elevatedUntil) {

ui/src/application/AppStore.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import axios from 'axios';
22
import {generateKeyBetween} from 'fractional-indexing';
3-
import {action, runInAction} from 'mobx';
3+
import {action, makeObservable, runInAction} from 'mobx';
44
import {BaseStore} from '../common/BaseStore';
55
import * as config from '../config';
66
import {SnackReporter} from '../snack/SnackManager';
@@ -12,6 +12,12 @@ export class AppStore extends BaseStore<IApplication> {
1212

1313
public constructor(private readonly snack: SnackReporter) {
1414
super();
15+
makeObservable(this, {
16+
uploadImage: action,
17+
reorder: action,
18+
update: action,
19+
create: action,
20+
});
1521
}
1622

1723
protected requestItems = (): Promise<IApplication[]> =>
@@ -25,7 +31,6 @@ export class AppStore extends BaseStore<IApplication> {
2531
return this.snack('Application deleted');
2632
});
2733

28-
@action
2934
public uploadImage = async (id: number, file: Blob): Promise<void> => {
3035
const formData = new FormData();
3136
formData.append('file', file);
@@ -57,7 +62,6 @@ export class AppStore extends BaseStore<IApplication> {
5762
}
5863
}
5964

60-
@action
6165
public reorder = async (fromId: number, toId: number): Promise<void> => {
6266
const fromIndex = this.items.findIndex((app) => app.id === fromId);
6367
const toIndex = this.items.findIndex((app) => app.id === toId);
@@ -80,7 +84,6 @@ export class AppStore extends BaseStore<IApplication> {
8084
await this.update({...toUpdate, sortKey: newSortKey});
8185
};
8286

83-
@action
8487
public update = async ({
8588
id,
8689
...app
@@ -93,7 +96,6 @@ export class AppStore extends BaseStore<IApplication> {
9396
this.snack('Application updated');
9497
};
9598

96-
@action
9799
public create = async (
98100
name: string,
99101
description: string,

ui/src/client/ClientStore.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
import {BaseStore} from '../common/BaseStore';
22
import axios from 'axios';
33
import * as config from '../config';
4-
import {action} from 'mobx';
4+
import {action, makeObservable} from 'mobx';
55
import {SnackReporter} from '../snack/SnackManager';
66
import {IClient} from '../types';
77

88
export class ClientStore extends BaseStore<IClient> {
99
public constructor(private readonly snack: SnackReporter) {
1010
super();
11+
makeObservable(this, {
12+
update: action,
13+
createNoNotifcation: action,
14+
create: action,
15+
elevate: action,
16+
});
1117
}
1218

1319
protected requestItems = (): Promise<IClient[]> =>
@@ -19,7 +25,6 @@ export class ClientStore extends BaseStore<IClient> {
1925
.then(() => this.snack('Client deleted'));
2026
}
2127

22-
@action
2328
public update = async (
2429
id: number,
2530
name: string,
@@ -33,7 +38,6 @@ export class ClientStore extends BaseStore<IClient> {
3338
this.snack('Client updated');
3439
};
3540

36-
@action
3741
public createNoNotifcation = async (
3842
name: string,
3943
expiresAfterInactivitySeconds = 0
@@ -46,14 +50,12 @@ export class ClientStore extends BaseStore<IClient> {
4650
return client.data;
4751
};
4852

49-
@action
5053
public create = async (name: string, expiresAfterInactivitySeconds = 0): Promise<string> => {
5154
const client = await this.createNoNotifcation(name, expiresAfterInactivitySeconds);
5255
this.snack('Client added');
5356
return client.token;
5457
};
5558

56-
@action
5759
public elevate = async (id: number, durationSeconds: number): Promise<void> => {
5860
await axios.post(`${config.get('url')}client/${id}/elevate`, {durationSeconds});
5961
await this.refresh();

ui/src/common/BaseStore.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {action, observable} from 'mobx';
1+
import {action, makeObservable, observable} from 'mobx';
22

33
interface HasID {
44
id: number;
@@ -12,27 +12,34 @@ export interface IClearable {
1212
* Base implementation for handling items with ids.
1313
*/
1414
export abstract class BaseStore<T extends HasID> implements IClearable {
15-
@observable protected accessor items: T[] = [];
15+
public items: T[] = [];
16+
17+
protected constructor() {
18+
makeObservable(this, {
19+
items: observable,
20+
remove: action,
21+
refresh: action,
22+
refreshIfMissing: action,
23+
clear: action,
24+
});
25+
}
1626

1727
protected abstract requestItems(): Promise<T[]>;
1828

1929
protected abstract requestDelete(id: number): Promise<void>;
2030

21-
@action
2231
public remove = async (id: number): Promise<void> => {
2332
await this.requestDelete(id);
2433
await this.refresh();
2534
};
2635

27-
@action
2836
public refresh = (): Promise<void> =>
2937
this.requestItems().then(
3038
action((items) => {
3139
this.items = items || [];
3240
})
3341
);
3442

35-
@action
3643
public refreshIfMissing = async (id: number): Promise<void> => {
3744
if (this.getByIDOrUndefined(id) === undefined) {
3845
await this.refresh();
@@ -52,7 +59,6 @@ export abstract class BaseStore<T extends HasID> implements IClearable {
5259

5360
public getItems = (): T[] => this.items;
5461

55-
@action
5662
public clear = (): void => {
5763
this.items = [];
5864
};

ui/src/message/MessagesStore.ts

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {BaseStore} from '../common/BaseStore';
2-
import {action, IObservableArray, observable, reaction, runInAction} from 'mobx';
2+
import {action, IObservableArray, makeObservable, observable, reaction, runInAction} from 'mobx';
33
import axios, {AxiosResponse} from 'axios';
44
import * as config from '../config';
55
import {createTransformer} from 'mobx-utils';
@@ -22,15 +22,33 @@ interface PendingDelete {
2222
}
2323

2424
export class MessagesStore {
25-
@observable private accessor state: Record<string, MessagesState> = {};
26-
@observable private accessor pendingDeletes: Map<number, PendingDelete> = observable.map();
25+
private state: Record<string, MessagesState> = {};
26+
private pendingDeletes: Map<number, PendingDelete> = observable.map();
2727

2828
private loading = false;
2929

3030
public constructor(
3131
private readonly appStore: BaseStore<IApplication>,
3232
private readonly snack: SnackReporter
3333
) {
34+
makeObservable<MessagesStore, 'state' | 'pendingDeletes' | 'removeFromList' | 'clear'>(
35+
this,
36+
{
37+
state: observable,
38+
pendingDeletes: observable,
39+
loadMore: action,
40+
publishSingleMessage: action,
41+
removeByApp: action,
42+
addPendingDelete: action,
43+
cancelPendingDelete: action,
44+
executePendingDeletes: action,
45+
removeSingle: action,
46+
clearAll: action,
47+
refreshByApp: action,
48+
removeFromList: action,
49+
clear: action,
50+
}
51+
);
3452
reaction(() => appStore.getItems(), this.createEmptyStatesForApps);
3553
}
3654

@@ -45,7 +63,6 @@ export class MessagesStore {
4563

4664
public canLoadMore = (appId: number) => this.stateOf(appId, /*create*/ false).hasMore;
4765

48-
@action
4966
public loadMore = async (appId: number) => {
5067
const state = this.stateOf(appId);
5168
if (!state.hasMore || this.loading) {
@@ -70,7 +87,6 @@ export class MessagesStore {
7087
return Promise.resolve();
7188
};
7289

73-
@action
7490
public publishSingleMessage = (message: IMessage) => {
7591
if (this.exists(AllMessages)) {
7692
this.stateOf(AllMessages).messages.unshift(message);
@@ -80,7 +96,6 @@ export class MessagesStore {
8096
}
8197
};
8298

83-
@action
8499
public removeByApp = async (appId: number) => {
85100
if (appId === AllMessages) {
86101
await axios.delete(config.get('url') + 'message');
@@ -95,11 +110,9 @@ export class MessagesStore {
95110
await this.loadMore(appId);
96111
};
97112

98-
@action
99113
public addPendingDelete = (pending: PendingDelete) =>
100114
this.pendingDeletes.set(pending.message.id, pending);
101115

102-
@action
103116
public cancelPendingDelete = (message: IMessage): boolean => {
104117
const pending = this.pendingDeletes.get(message.id);
105118
if (pending) {
@@ -109,13 +122,11 @@ export class MessagesStore {
109122
return !!pending;
110123
};
111124

112-
@action
113125
public executePendingDeletes = () =>
114126
Array.from(this.pendingDeletes.values()).forEach(({message}) => this.removeSingle(message));
115127

116128
public visible = (message: number): boolean => !this.pendingDeletes.has(message);
117129

118-
@action
119130
public removeSingle = async (message: IMessage) => {
120131
if (!this.pendingDeletes.has(message.id)) {
121132
return;
@@ -152,21 +163,18 @@ export class MessagesStore {
152163
this.snack(`Message sent to ${app.name}`);
153164
};
154165

155-
@action
156166
public clearAll = () => {
157167
this.state = {};
158168
this.createEmptyStatesForApps(this.appStore.getItems());
159169
};
160170

161-
@action
162171
public refreshByApp = async (appId: number) => {
163172
this.clearAll();
164173
this.loadMore(appId);
165174
};
166175

167176
public exists = (id: number) => this.stateOf(id).loaded;
168177

169-
@action
170178
private removeFromList(messages: IMessage[], messageToDelete: IMessage): false | number {
171179
if (messages) {
172180
const index = messages.findIndex((message) => message.id === messageToDelete.id);
@@ -178,7 +186,6 @@ export class MessagesStore {
178186
return false;
179187
}
180188

181-
@action
182189
private clear = (appId: number) => (this.state[appId] = this.emptyState());
183190

184191
private fetchMessages = (

ui/src/plugin/PluginStore.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import axios from 'axios';
2-
import {action} from 'mobx';
2+
import {action, makeObservable} from 'mobx';
33
import {BaseStore} from '../common/BaseStore';
44
import * as config from '../config';
55
import {SnackReporter} from '../snack/SnackManager';
@@ -10,6 +10,10 @@ export class PluginStore extends BaseStore<IPlugin> {
1010

1111
public constructor(private readonly snack: SnackReporter) {
1212
super();
13+
makeObservable(this, {
14+
changeConfig: action,
15+
changeEnabledState: action,
16+
});
1317
}
1418

1519
public requestConfig = (id: number): Promise<string> =>
@@ -31,7 +35,6 @@ export class PluginStore extends BaseStore<IPlugin> {
3135
return id === -1 ? 'All Plugins' : plugin !== undefined ? plugin.name : 'unknown';
3236
};
3337

34-
@action
3538
public changeConfig = async (id: number, newConfig: string): Promise<void> => {
3639
await axios.post(`${config.get('url')}plugin/${id}/config`, newConfig, {
3740
headers: {'content-type': 'application/x-yaml'},
@@ -40,7 +43,6 @@ export class PluginStore extends BaseStore<IPlugin> {
4043
await this.refresh();
4144
};
4245

43-
@action
4446
public changeEnabledState = async (id: number, enabled: boolean): Promise<void> => {
4547
await axios.post(`${config.get('url')}plugin/${id}/${enabled ? 'enable' : 'disable'}`);
4648
this.snack(`Plugin ${enabled ? 'enabled' : 'disabled'}`);

0 commit comments

Comments
 (0)