Skip to content

Commit 3595665

Browse files
authored
Merge pull request #474 from appuniversum/chore/more-gts
More Glint / TS conversion
2 parents 47dcdd2 + c03bca1 commit 3595665

34 files changed

+885
-416
lines changed

addon/components/au-fieldset.gjs addon/components/au-fieldset.gts

+42-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,25 @@
1-
import { AuBadge, AuPill } from '@appuniversum/ember-appuniversum';
1+
import type { TOC } from '@ember/component/template-only';
22
import { hash } from '@ember/helper';
33
import Component from '@glimmer/component';
4+
import AuBadge from './au-badge';
5+
import AuPill from './au-pill';
46

5-
export default class AuFieldset extends Component {
7+
export interface AuFieldsetSignature {
8+
Args: {
9+
alignment?: 'inline';
10+
};
11+
Blocks: {
12+
default: [
13+
{
14+
legend?: typeof Legend;
15+
content?: typeof Content;
16+
},
17+
];
18+
};
19+
Element: HTMLFieldSetElement;
20+
}
21+
22+
export default class AuFieldset extends Component<AuFieldsetSignature> {
623
get alignment() {
724
if (this.args.alignment == 'inline') return 'au-c-fieldset--inline';
825
else return '';
@@ -16,7 +33,22 @@ export default class AuFieldset extends Component {
1633
</template>
1734
}
1835

19-
class Legend extends Component {
36+
interface LegendSignature {
37+
Args: {
38+
error?: boolean;
39+
inline?: boolean;
40+
required?: boolean;
41+
requiredLabel?: string;
42+
skin?: '1' | '2' | '3' | '4' | '5' | '6' | 'functional';
43+
warning?: boolean;
44+
};
45+
Blocks: {
46+
default: [];
47+
};
48+
Element: HTMLDivElement;
49+
}
50+
51+
class Legend extends Component<LegendSignature> {
2052
get skin() {
2153
if (this.args.skin == '1') return 'au-u-h1';
2254
if (this.args.skin == '2') return 'au-u-h2';
@@ -86,7 +118,13 @@ class Legend extends Component {
86118
</template>
87119
}
88120

89-
const Content = <template>
121+
interface ContentSignature {
122+
Blocks: {
123+
default: [];
124+
};
125+
Element: HTMLDivElement;
126+
}
127+
const Content: TOC<ContentSignature> = <template>
90128
{{#if (has-block)}}
91129
<div class="au-c-fieldset__content" ...attributes>
92130
{{yield}}

addon/components/au-file-card.gjs addon/components/au-file-card.gts

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
1-
import { AuHeading, AuIcon } from '@appuniversum/ember-appuniversum';
21
import { on } from '@ember/modifier';
32
import { action } from '@ember/object';
43
import Component from '@glimmer/component';
4+
import AuHeading from './au-heading';
5+
import AuIcon from './au-icon';
56

6-
export default class AuFileCard extends Component {
7+
export interface AuFileCardSignature {
8+
Args: {
9+
filename: string;
10+
fileSize?: string;
11+
downloadLink?: string;
12+
onDelete?: () => void;
13+
};
14+
Element: HTMLElement;
15+
}
16+
17+
export default class AuFileCard extends Component<AuFileCardSignature> {
718
get isRemovable() {
819
return typeof this.args.onDelete === 'function';
920
}
@@ -16,9 +27,9 @@ export default class AuFileCard extends Component {
1627
}
1728

1829
@action
19-
delete(event) {
30+
delete(event: Event) {
2031
event.preventDefault();
21-
this.args.onDelete();
32+
this.args.onDelete?.();
2233
}
2334

2435
<template>

addon/components/au-file-upload.gjs addon/components/au-file-upload.gts

+86-43
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,51 @@
1-
import { AuAlert, AuHelpText, AuIcon } from '@appuniversum/ember-appuniversum';
21
import { action } from '@ember/object';
32
import { guidFor } from '@ember/object/internals';
43
import { inject as service } from '@ember/service';
54
import Component from '@glimmer/component';
65
import { tracked } from '@glimmer/tracking';
76
import { task } from 'ember-concurrency';
8-
import perform from 'ember-concurrency/helpers/perform';
97
import FileDropzone from 'ember-file-upload/components/file-dropzone';
108
import fileQueue from 'ember-file-upload/helpers/file-queue';
9+
import type { FileQueueService, UploadFile } from 'ember-file-upload';
10+
import AuAlert from './au-alert';
11+
import AuHelpText from './au-help-text';
12+
import AuIcon from './au-icon';
13+
14+
export interface AuFileUploadSignature {
15+
Args: {
16+
accept?: string;
17+
endPoint?: string;
18+
helpTextDragDrop?: string;
19+
helpTextFileNotSupported?: string;
20+
maxFileSizeMB?: number;
21+
multiple?: boolean;
22+
onFinishUpload?: (uploadedFile: number, queueInfo: QueueInfo) => void;
23+
onQueueUpdate?: (queueInfo: QueueInfo) => void;
24+
title?: string;
25+
};
26+
// ember-file-upload doesn't seem to expose the signature of the FileDropzone component
27+
// We just hardcode what they have defined in the addon for now.
28+
Element: HTMLElement;
29+
}
30+
31+
export type QueueInfo = {
32+
isQueueEmpty: boolean;
33+
};
34+
35+
// A simpler version of the File and UploadFile types
36+
type BasicFile = {
37+
name: string;
38+
type: string;
39+
};
40+
41+
type UploadError = {
42+
filename: string;
43+
error?: string;
44+
};
1145

12-
export default class AuFileUpload extends Component {
13-
@service fileQueue;
14-
@tracked uploadErrorData = [];
46+
export default class AuFileUpload extends Component<AuFileUploadSignature> {
47+
@service declare fileQueue: FileQueueService;
48+
@tracked uploadErrorData: UploadError[] = [];
1549

1650
get uploadingMsg() {
1751
return `Bezig met het opladen van ${this.queue.files.length} bestand(en). (${this.queue.progress}%)`;
@@ -55,37 +89,43 @@ export default class AuFileUpload extends Component {
5589
return this.uploadErrorData.length > 0;
5690
}
5791

58-
@task
59-
*upload(file) {
92+
@action
93+
upload(file: UploadFile): void | undefined {
94+
this.uploadTask.perform(file);
95+
}
96+
97+
uploadTask = task(async (file: UploadFile) => {
6098
this.resetErrors();
61-
let uploadedFile = yield this.uploadFileTask.perform(file);
99+
const uploadedFile = await this.uploadFileTask.perform(file);
62100

63101
this.notifyQueueUpdate();
64102

65103
if (uploadedFile && this.args.onFinishUpload)
66104
this.args.onFinishUpload(uploadedFile, this.calculateQueueInfo());
67-
}
105+
});
68106

69-
@task({ enqueue: true, maxConcurrency: 3 })
70-
*uploadFileTask(file) {
71-
this.notifyQueueUpdate();
72-
try {
73-
const response = yield file.upload(this.endPoint, {
74-
'Content-Type': 'multipart/form-data',
75-
});
76-
const body = yield response.json();
77-
const fileId = body?.data?.id;
78-
return fileId;
79-
} catch (e) {
80-
this.addError(file);
81-
this.removeFileFromQueue(file);
82-
return null;
83-
}
84-
}
107+
uploadFileTask = task(
108+
{ enqueue: true, maxConcurrency: 3 },
109+
async (file: UploadFile): Promise<number | null> => {
110+
this.notifyQueueUpdate();
111+
try {
112+
const response = await file.upload(this.endPoint, {
113+
contentType: 'multipart/form-data',
114+
});
115+
const body = await response.json();
116+
const fileId = body?.data?.id;
117+
return fileId;
118+
} catch (e) {
119+
this.addError(file);
120+
this.removeFileFromQueue(file);
121+
return null;
122+
}
123+
},
124+
);
85125

86126
@action
87-
filter(file, files, index) {
88-
let isFirstFile = index === 0;
127+
filter(file: File, files: File[], index: number) {
128+
const isFirstFile = index === 0;
89129

90130
if (isFirstFile) {
91131
this.resetErrors();
@@ -115,14 +155,14 @@ export default class AuFileUpload extends Component {
115155
}
116156
}
117157

118-
calculateQueueInfo() {
158+
calculateQueueInfo(): QueueInfo {
119159
const filesQueueInfo = {
120160
isQueueEmpty: this.uploadFileTask.isIdle,
121161
};
122162
return filesQueueInfo;
123163
}
124164

125-
addError(file, errorMessage) {
165+
addError(file: BasicFile, errorMessage?: string) {
126166
this.uploadErrorData = [
127167
...this.uploadErrorData,
128168
{
@@ -136,13 +176,13 @@ export default class AuFileUpload extends Component {
136176
this.uploadErrorData = [];
137177
}
138178

139-
removeFileFromQueue(file) {
179+
removeFileFromQueue(file: UploadFile) {
140180
this.queue.remove(file);
141181
}
142182

143183
<template>
144184
{{#let
145-
(fileQueue name=this.queueName onFileAdded=(perform this.upload))
185+
(fileQueue name=this.queueName onFileAdded=this.uploadTask.perform)
146186
as |queue|
147187
}}
148188
<FileDropzone
@@ -212,39 +252,39 @@ export default class AuFileUpload extends Component {
212252
}
213253

214254
// Private util that is exported for testing purposes
215-
export function isValidFileType(file, accept) {
255+
export function isValidFileType(file: Partial<BasicFile>, accept?: string) {
216256
if (!accept) {
217257
return true;
218258
}
219259

220-
let tokens = accept.split(',').map(function (token) {
260+
const tokens = accept.split(',').map(function (token) {
221261
return token.trim().toLowerCase();
222262
});
223263

224-
let validMimeTypes = tokens.filter(function (token) {
264+
const validMimeTypes = tokens.filter(function (token) {
225265
return !token.startsWith('.');
226266
});
227-
let type = file.type?.toLowerCase();
267+
const type = file.type?.toLowerCase();
228268

229-
let validExtensions = tokens.filter(function (token) {
269+
const validExtensions = tokens.filter(function (token) {
230270
return token.startsWith('.');
231271
});
232272

233273
let extension = null;
234274
if (file.name && /(\.[^.]+)$/.test(file.name)) {
235-
extension = file.name.toLowerCase().match(/(\.[^.]+)$/)[1];
275+
extension = file.name.toLowerCase().match(/(\.[^.]+)$/)?.[1];
236276
}
237277

238278
return (
239-
isValidMimeType(type, validMimeTypes) ||
240-
isValidExtension(extension, validExtensions)
279+
(!!type && isValidMimeType(type, validMimeTypes)) ||
280+
(!!extension && isValidExtension(extension, validExtensions))
241281
);
242282
}
243283

244-
function isValidMimeType(type, validMimeTypes = []) {
284+
function isValidMimeType(type: string, validMimeTypes: string[] = []) {
245285
return validMimeTypes.some(function (validType) {
246286
if (['audio/*', 'video/*', 'image/*'].includes(validType)) {
247-
let genericType = validType.split('/')[0];
287+
const genericType = validType.split('/')[0] as string;
248288

249289
return type.startsWith(genericType);
250290
} else {
@@ -253,10 +293,13 @@ function isValidMimeType(type, validMimeTypes = []) {
253293
});
254294
}
255295

256-
function isValidExtension(extension, validExtensions = []) {
296+
function isValidExtension(
297+
extension: string,
298+
validExtensions: string[] = [],
299+
): boolean {
257300
return validExtensions.includes(extension);
258301
}
259302

260-
function isValidFileSize(fileSize, maximumSize) {
303+
function isValidFileSize(fileSize: number, maximumSize: number): boolean {
261304
return fileSize < maximumSize * Math.pow(1024, 2);
262305
}

addon/components/au-label.gjs addon/components/au-label.gts

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
11
import Component from '@glimmer/component';
2-
import { AuBadge, AuPill } from '@appuniversum/ember-appuniversum';
2+
import AuBadge from './au-badge';
3+
import AuPill from './au-pill';
34

4-
export default class AuLabel extends Component {
5+
export interface AuLabelSignature {
6+
Args: {
7+
error?: boolean;
8+
inline?: boolean;
9+
required?: boolean;
10+
requiredLabel?: string;
11+
warning?: boolean;
12+
};
13+
Blocks: {
14+
default: [];
15+
};
16+
Element: HTMLLabelElement;
17+
}
18+
19+
export default class AuLabel extends Component<AuLabelSignature> {
520
get inline() {
621
if (this.args.inline) return 'au-c-label--inline';
722
else return '';

0 commit comments

Comments
 (0)