Skip to content

Commit

Permalink
Merge pull request #3174 from flarum/as/models-typing
Browse files Browse the repository at this point in the history
Typescript for models
  • Loading branch information
askvortsov1 authored Dec 13, 2021
2 parents bd8ebb0 + f26ad3e commit 187b5c6
Show file tree
Hide file tree
Showing 28 changed files with 1,140 additions and 872 deletions.
11 changes: 11 additions & 0 deletions js/src/@types/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,17 @@ declare const app: never;
declare const m: import('mithril').Static;
declare const dayjs: typeof import('dayjs');

/**
* From https://github.com/lokesh/color-thief/issues/188
*/
declare module 'color-thief-browser' {
type Color = [number, number, number];
export default class ColorThief {
getColor: (img: HTMLImageElement | null) => Color;
getPalette: (img: HTMLImageElement | null) => Color[];
}
}

type ESModule = { __esModule: true; [key: string]: unknown };

/**
Expand Down
4 changes: 2 additions & 2 deletions js/src/admin/AdminApplication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ export default class AdminApplication extends Application {
history = {
canGoBack: () => true,
getPrevious: () => {},
backUrl: () => this.forum.attribute('baseUrl'),
backUrl: () => this.forum.attribute<string>('baseUrl'),
back: function () {
window.location = this.backUrl();
window.location.assign(this.backUrl());
},
};

Expand Down
24 changes: 7 additions & 17 deletions js/src/admin/components/UserListPage.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type Mithril from 'mithril';

import app from '../../admin/app';

import EditUserModal from '../../common/components/EditUserModal';
Expand All @@ -14,7 +16,6 @@ import classList from '../../common/utils/classList';
import extractText from '../../common/utils/extractText';

import AdminPage from './AdminPage';
import Mithril from 'mithril';

type ColumnData = {
/**
Expand All @@ -24,20 +25,9 @@ type ColumnData = {
/**
* Component(s) to show for this column.
*/
content: (user: User) => JSX.Element;
};

type ApiPayload = {
data: Record<string, unknown>[];
included: Record<string, unknown>[];
links: {
first: string;
next?: string;
};
content: (user: User) => Mithril.Children;
};

type UsersApiResponse = User[] & { payload: ApiPayload };

/**
* Admin page which displays a paginated list of all users on the forum.
*/
Expand Down Expand Up @@ -185,7 +175,7 @@ export default class UserListPage extends AdminPage {
'id',
{
name: app.translator.trans('core.admin.users.grid.columns.user_id.title'),
content: (user: User) => user.id(),
content: (user: User) => user.id() ?? '',
},
100
);
Expand Down Expand Up @@ -348,15 +338,15 @@ export default class UserListPage extends AdminPage {
if (pageNumber < 0) pageNumber = 0;

app.store
.find('users', {
.find<User[]>('users', {
page: {
limit: this.numPerPage,
offset: pageNumber * this.numPerPage,
},
})
.then((apiData: UsersApiResponse) => {
.then((apiData) => {
// Next link won't be present if there's no more data
this.moreData = !!apiData.payload.links.next;
this.moreData = !!apiData.payload?.links?.next;

let data = apiData;

Expand Down
21 changes: 13 additions & 8 deletions js/src/common/Application.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import ModalManager from './components/ModalManager';
import AlertManager from './components/AlertManager';
import RequestErrorModal from './components/RequestErrorModal';
import Translator from './Translator';
import Store from './Store';
import Store, { ApiPayload, ApiResponse, ApiResponsePlural, ApiResponseSingle, payloadIsPlural } from './Store';
import Session from './Session';
import extract from './utils/extract';
import Drawer from './utils/Drawer';
Expand All @@ -31,6 +31,7 @@ import type DefaultResolver from './resolvers/DefaultResolver';
import type Mithril from 'mithril';
import type Component from './Component';
import type { ComponentAttrs } from './Component';
import Model, { SavedModelData } from './Model';

export type FlarumScreens = 'phone' | 'tablet' | 'desktop' | 'desktop-hd';

Expand Down Expand Up @@ -210,10 +211,10 @@ export default class Application {
drawer!: Drawer;

data!: {
apiDocument: Record<string, unknown> | null;
apiDocument: ApiPayload | null;
locale: string;
locales: Record<string, string>;
resources: Record<string, unknown>[];
resources: SavedModelData[];
session: { userId: number; csrfToken: string };
[key: string]: unknown;
};
Expand Down Expand Up @@ -255,9 +256,9 @@ export default class Application {

this.store.pushPayload({ data: this.data.resources });

this.forum = this.store.getById('forums', 1);
this.forum = this.store.getById('forums', '1')!;

this.session = new Session(this.store.getById('users', this.data.session.userId), this.data.session.csrfToken);
this.session = new Session(this.store.getById<User>('users', String(this.data.session.userId)) ?? null, this.data.session.csrfToken);

this.mount();

Expand Down Expand Up @@ -317,10 +318,14 @@ export default class Application {
/**
* Get the API response document that has been preloaded into the application.
*/
preloadedApiDocument(): Record<string, unknown> | null {
preloadedApiDocument<M extends Model>(): ApiResponseSingle<M> | null;
preloadedApiDocument<Ms extends Model[]>(): ApiResponsePlural<Ms[number]> | null;
preloadedApiDocument<M extends Model | Model[]>(): ApiResponse<FlatArray<M, 1>> | null {
// If the URL has changed, the preloaded Api document is invalid.
if (this.data.apiDocument && window.location.href === this.initialRoute) {
const results = this.store.pushPayload(this.data.apiDocument);
const results = payloadIsPlural(this.data.apiDocument)
? this.store.pushPayload<FlatArray<M, 1>[]>(this.data.apiDocument)
: this.store.pushPayload<FlatArray<M, 1>>(this.data.apiDocument);

this.data.apiDocument = null;

Expand Down Expand Up @@ -450,7 +455,7 @@ export default class Application {
* @param options
* @return {Promise}
*/
request<ResponseType>(originalOptions: FlarumRequestOptions<ResponseType>): Promise<ResponseType | string> {
request<ResponseType>(originalOptions: FlarumRequestOptions<ResponseType>): Promise<ResponseType> {
const options = this.transformRequestOptions(originalOptions);

if (this.requestErrorAlert) this.alerts.dismiss(this.requestErrorAlert);
Expand Down
Loading

0 comments on commit 187b5c6

Please sign in to comment.