Skip to content

Commit c519e61

Browse files
committed
migrate login to typescript
1 parent e0c6b4e commit c519e61

1 file changed

Lines changed: 58 additions & 48 deletions

File tree

  • src/apps/legacy/controllers/session/login

src/apps/legacy/controllers/session/login/index.js renamed to src/apps/legacy/controllers/session/login/index.ts

Lines changed: 58 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,22 @@ import toast from 'components/toast/toast';
1919
import dialogHelper from 'components/dialogHelper/dialogHelper';
2020
import baseAlert from 'components/alert';
2121
import { getDefaultBackgroundClass } from 'components/cardbuilder/utils/builder';
22+
import type { ApiClient } from 'jellyfin-apiclient';
23+
import type { BrandingOptionsDto, UserDto } from '@jellyfin/sdk/lib/generated-client';
2224

2325
import './login.scss';
2426

2527
const enableFocusTransform = !browser.slow && !browser.edge;
2628

27-
function authenticateUserByName(page, apiClient, url, username, password) {
29+
function authenticateUserByName(page: HTMLElement, apiClient: ApiClient, url: string, username: string, password: string) {
2830
loading.show();
2931
apiClient.authenticateUserByName(username, password).then(function (result) {
30-
const user = result.User;
32+
const user = result.User as UserDto;
3133
loading.hide();
3234

3335
onLoginSuccessful(user.Id, result.AccessToken, apiClient, url);
3436
}, function (response) {
35-
page.querySelector('#txtManualPassword').value = '';
37+
(page.querySelector('#txtManualPassword') as HTMLInputElement).value = '';
3638
loading.hide();
3739

3840
const UnauthorizedOrForbidden = [401, 403];
@@ -48,15 +50,17 @@ function authenticateUserByName(page, apiClient, url, username, password) {
4850
});
4951
}
5052

51-
function authenticateQuickConnect(apiClient, targetUrl) {
53+
function authenticateQuickConnect(apiClient: ApiClient, targetUrl: string) {
5254
const url = apiClient.getUrl('/QuickConnect/Initiate');
55+
// @ts-expect-error: The signature of ajax has just one argument. TODO: This should be investigated
5356
apiClient.ajax({ type: 'POST', url }, true).then(res => res.json()).then(function (json) {
5457
if (!json.Secret || !json.Code) {
5558
console.error('Malformed quick connect response', json);
5659
return false;
5760
}
5861

59-
baseAlert({
62+
// Should we be awaiting this promise?
63+
void baseAlert({
6064
dialogOptions: {
6165
id: 'quickConnectAlert'
6266
},
@@ -81,7 +85,7 @@ function authenticateQuickConnect(apiClient, targetUrl) {
8185
}
8286

8387
const result = await apiClient.quickConnect(data.Secret);
84-
onLoginSuccessful(result.User.Id, result.AccessToken, apiClient, targetUrl);
88+
onLoginSuccessful((result.User as UserDto).Id, result.AccessToken, apiClient, targetUrl);
8589
}, function (e) {
8690
clearInterval(interval);
8791

@@ -112,31 +116,32 @@ function authenticateQuickConnect(apiClient, targetUrl) {
112116
});
113117
}
114118

115-
function onLoginSuccessful(id, accessToken, apiClient, url) {
119+
function onLoginSuccessful(id: string | null | undefined, accessToken: string | null | undefined, apiClient: ApiClient, url: string) {
116120
Dashboard.onServerChanged(id, accessToken, apiClient);
117-
Dashboard.navigate(url || 'home');
121+
// Should we be handling the promise from navigate?
122+
void Dashboard.navigate(url || 'home');
118123
}
119124

120-
function showManualForm(context, showCancel, focusPassword) {
121-
context.querySelector('.chkRememberLogin').checked = appSettings.enableAutoLogin();
122-
context.querySelector('.manualLoginForm').classList.remove('hide');
123-
context.querySelector('.visualLoginForm').classList.add('hide');
124-
context.querySelector('.btnManual').classList.add('hide');
125+
function showManualForm(context: HTMLElement, showCancel: boolean, focusPassword?: boolean) {
126+
(context.querySelector('.chkRememberLogin') as HTMLInputElement).checked = appSettings.enableAutoLogin();
127+
(context.querySelector('.manualLoginForm') as Element).classList.remove('hide');
128+
(context.querySelector('.visualLoginForm') as Element).classList.add('hide');
129+
(context.querySelector('.btnManual') as Element).classList.add('hide');
125130

126131
if (focusPassword) {
127-
context.querySelector('#txtManualPassword').focus();
132+
(context.querySelector('#txtManualPassword') as HTMLInputElement).focus();
128133
} else {
129-
context.querySelector('#txtManualName').focus();
134+
(context.querySelector('#txtManualName') as HTMLElement).focus();
130135
}
131136

132137
if (showCancel) {
133-
context.querySelector('.btnCancel').classList.remove('hide');
138+
(context.querySelector('.btnCancel') as Element).classList.remove('hide');
134139
} else {
135-
context.querySelector('.btnCancel').classList.add('hide');
140+
(context.querySelector('.btnCancel') as Element).classList.add('hide');
136141
}
137142
}
138143

139-
function loadUserList(context, apiClient, users) {
144+
function loadUserList(context: HTMLElement, apiClient: ApiClient, users: UserDto[]) {
140145
let html = '';
141146

142147
for (const user of users) {
@@ -160,7 +165,7 @@ function loadUserList(context, apiClient, users) {
160165
let imgUrl;
161166

162167
if (user.PrimaryImageTag) {
163-
imgUrl = apiClient.getUserImageUrl(user.Id, {
168+
imgUrl = apiClient.getUserImageUrl(user.Id as string, {
164169
width: 300,
165170
tag: user.PrimaryImageTag,
166171
type: 'Primary'
@@ -182,17 +187,19 @@ function loadUserList(context, apiClient, users) {
182187
html += '</button>';
183188
}
184189

185-
context.querySelector('#divUsers').innerHTML = html;
190+
(context.querySelector('#divUsers') as Element).innerHTML = html;
186191
}
187192

188-
export default function (view, params) {
189-
function getApiClient() {
193+
export default function (view: HTMLElement, params: Record<string, string>) {
194+
function getApiClient(): ApiClient {
190195
const serverId = params.serverid;
191196

192197
if (serverId) {
193198
return ServerConnections.getOrCreateApiClient(serverId);
194199
}
195200

201+
// TODO: This should be investigated
202+
// @ts-expect-error: It appears we're returning a type definition here instead of an instance of the object, but this code works, so it's not as it seems
196203
return ApiClient;
197204
}
198205

@@ -209,56 +216,57 @@ export default function (view, params) {
209216
}
210217

211218
function showVisualForm() {
212-
view.querySelector('.visualLoginForm').classList.remove('hide');
213-
view.querySelector('.manualLoginForm').classList.add('hide');
214-
view.querySelector('.btnManual').classList.remove('hide');
219+
(view.querySelector('.visualLoginForm') as Element).classList.remove('hide');
220+
(view.querySelector('.manualLoginForm') as Element).classList.add('hide');
221+
(view.querySelector('.btnManual') as Element).classList.remove('hide');
215222

216-
import('components/autoFocuser').then(({ default: autoFocuser }) => {
223+
// Should we be handling this promise?
224+
void import('components/autoFocuser').then(({ default: autoFocuser }) => {
217225
autoFocuser.autoFocus(view);
218226
});
219227
}
220228

221-
view.querySelector('#divUsers').addEventListener('click', function (e) {
222-
const card = dom.parentWithClass(e.target, 'card');
229+
(view.querySelector('#divUsers') as Element).addEventListener('click', function (e) {
230+
const card = dom.parentWithClass(e.target as HTMLElement, 'card');
223231
const cardContent = card ? card.querySelector('.cardContent') : null;
224232

225233
if (cardContent) {
226234
const context = view;
227235
const id = cardContent.getAttribute('data-userid');
228-
const name = cardContent.getAttribute('data-username');
236+
const name = cardContent.getAttribute('data-username') as string;
229237
const haspw = cardContent.getAttribute('data-haspw');
230238

231239
if (id === 'manual') {
232-
context.querySelector('#txtManualName').value = '';
240+
(context.querySelector('#txtManualName') as HTMLInputElement).value = '';
233241
showManualForm(context, true);
234242
} else if (haspw == 'false') {
235243
authenticateUserByName(context, getApiClient(), getTargetUrl(), name, '');
236244
} else {
237-
context.querySelector('#txtManualName').value = name;
238-
context.querySelector('#txtManualPassword').value = '';
245+
(context.querySelector('#txtManualName') as HTMLInputElement).value = name;
246+
(context.querySelector('#txtManualPassword') as HTMLInputElement).value = '';
239247
showManualForm(context, true, true);
240248
}
241249
}
242250
});
243-
view.querySelector('.manualLoginForm').addEventListener('submit', function (e) {
244-
appSettings.enableAutoLogin(view.querySelector('.chkRememberLogin').checked);
245-
authenticateUserByName(view, getApiClient(), getTargetUrl(), view.querySelector('#txtManualName').value, view.querySelector('#txtManualPassword').value);
251+
(view.querySelector('.manualLoginForm') as Element).addEventListener('submit', function (e) {
252+
appSettings.enableAutoLogin((view.querySelector('.chkRememberLogin') as HTMLInputElement).checked);
253+
authenticateUserByName(view, getApiClient(), getTargetUrl(), (view.querySelector('#txtManualName') as HTMLInputElement).value, (view.querySelector('#txtManualPassword') as HTMLInputElement).value);
246254
e.preventDefault();
247255
return false;
248256
});
249-
view.querySelector('.btnForgotPassword').addEventListener('click', function () {
250-
Dashboard.navigate('forgotpassword');
257+
(view.querySelector('.btnForgotPassword') as Element).addEventListener('click', function () {
258+
void Dashboard.navigate('forgotpassword');
251259
});
252-
view.querySelector('.btnCancel').addEventListener('click', showVisualForm);
253-
view.querySelector('.btnQuick').addEventListener('click', function () {
260+
(view.querySelector('.btnCancel') as Element).addEventListener('click', showVisualForm);
261+
(view.querySelector('.btnQuick') as Element).addEventListener('click', function () {
254262
authenticateQuickConnect(getApiClient(), getTargetUrl());
255263
return false;
256264
});
257-
view.querySelector('.btnManual').addEventListener('click', function () {
258-
view.querySelector('#txtManualName').value = '';
265+
(view.querySelector('.btnManual') as Element).addEventListener('click', function () {
266+
(view.querySelector('#txtManualName') as HTMLInputElement).value = '';
259267
showManualForm(view, true);
260268
});
261-
view.querySelector('.btnSelectServer').addEventListener('click', function () {
269+
(view.querySelector('.btnSelectServer') as Element).addEventListener('click', function () {
262270
Dashboard.selectServer();
263271
});
264272

@@ -267,34 +275,36 @@ export default function (view, params) {
267275
libraryMenu.setTransparentMenu(true);
268276

269277
if (!appHost.supports(AppFeature.MultiServer)) {
270-
view.querySelector('.btnSelectServer').classList.add('hide');
278+
(view.querySelector('.btnSelectServer') as Element).classList.add('hide');
271279
}
272280

273281
const apiClient = getApiClient();
274282

275283
apiClient.getQuickConnect('Enabled')
276284
.then(enabled => {
277285
if (enabled === true) {
278-
view.querySelector('.btnQuick').classList.remove('hide');
286+
(view.querySelector('.btnQuick') as Element).classList.remove('hide');
279287
}
280288
})
281289
.catch(() => {
282290
console.debug('Failed to get QuickConnect status');
283291
});
284292

285-
apiClient.getPublicUsers().then(function (users) {
293+
// Should we be awaiting this promise?
294+
void apiClient.getPublicUsers().then(function (users) {
286295
if (users.length) {
287296
showVisualForm();
288297
loadUserList(view, apiClient, users);
289298
} else {
290-
view.querySelector('#txtManualName').value = '';
299+
(view.querySelector('#txtManualName') as HTMLInputElement).value = '';
291300
showManualForm(view, false, false);
292301
}
293302
}).catch().then(function () {
294303
loading.hide();
295304
});
296-
apiClient.getJSON(apiClient.getUrl('Branding/Configuration')).then(function (options) {
297-
const loginDisclaimer = view.querySelector('.loginDisclaimer');
305+
// Should this promise be awaited?
306+
void apiClient.getJSON(apiClient.getUrl('Branding/Configuration')).then(function (options: BrandingOptionsDto) {
307+
const loginDisclaimer = (view.querySelector('.loginDisclaimer') as Element);
298308

299309
// eslint-disable-next-line sonarjs/disabled-auto-escaping
300310
loginDisclaimer.innerHTML = DOMPurify.sanitize(markdownIt({ html: true }).render(options.LoginDisclaimer || ''));

0 commit comments

Comments
 (0)