Regenerate types

This commit is contained in:
Piotr Rogowski 2022-11-05 16:32:11 +01:00
parent efabc6ee2a
commit 30af59f8c9
No known key found for this signature in database
GPG Key ID: 4A842D702D9C6F8F
12 changed files with 92 additions and 100 deletions

View File

@ -7,11 +7,12 @@ export type RecordIdString = string
export type UserIdString = string
export type BaseRecord = {
id: RecordIdString
created: IsoDateString
updated: IsoDateString
collectionId: string
collectionName: string
id: RecordIdString
created: IsoDateString
updated: IsoDateString
collectionId: string
collectionName: string
expand?: { [key: string]: any }
}
export enum Collections {
@ -26,6 +27,8 @@ export type IniFilesRecord = {
ecosystem: 'speeduino' | 'rusefi'
}
export type IniFilesResponse = IniFilesRecord & BaseRecord
export type TunesRecord = {
author: RecordIdString
tuneId: string
@ -52,10 +55,17 @@ export type TunesRecord = {
toothLogFiles?: string[]
}
export type TunesResponse = TunesRecord & BaseRecord
export type UsersRecord = {
avatar?: string
username: string
email: string
verified: boolean
}
export type UsersResponse = UsersRecord & BaseRecord
export type CollectionRecords = {
iniFiles: IniFilesRecord
tunes: TunesRecord

View File

@ -34,7 +34,6 @@ import Info from './pages/Info';
import Hub from './pages/Hub';
import { FormRoles } from './pages/auth/Login';
import useServerStorage from './hooks/useServerStorage';
import { TunesRecordFull } from './types/dbData';
import TuneParser from './utils/tune/TuneParser';
import standardDialogs from './data/standardDialogs';
import help from './data/help';
@ -52,6 +51,7 @@ import {
import 'uplot/dist/uPlot.min.css';
import 'react-perfect-scrollbar/dist/css/styles.css';
import './css/App.less';
import { TunesResponse } from './@types/pocketbase-types';
const Tune = lazy(() => import('./pages/Tune'));
const Logs = lazy(() => import('./pages/Logs'));
@ -83,7 +83,7 @@ const App = ({ ui, tuneData }: { ui: UIState, tuneData: TuneDataState }) => {
const tuneId = tunePathMatch?.params.tuneId;
const { fetchINIFile, fetchTuneFile } = useServerStorage();
const loadTune = async (data: TunesRecordFull | null) => {
const loadTune = async (data: TunesResponse | null) => {
if (data === null) {
store.dispatch({ type: 'config/load', payload: null });
store.dispatch({ type: 'tune/load', payload: null });

View File

@ -11,9 +11,11 @@ import {
formatError,
} from '../pocketbase';
import { buildRedirectUrl } from '../utils/url';
import { Collections } from '../@types/pocketbase-types';
import {
Collections,
UsersResponse,
} from '../@types/pocketbase-types';
import { Routes } from '../routes';
import { UsersRecordFull } from '../types/dbData';
// TODO: this should be imported from pocketbase but currently is not exported
export type AuthProviderInfo = {
@ -39,10 +41,10 @@ export enum OAuthProviders {
};
interface AuthValue {
currentUser: UsersRecordFull | null,
signUp: (email: string, password: string, username: string) => Promise<UsersRecordFull>,
login: (email: string, password: string) => Promise<UsersRecordFull>,
refreshUser: () => Promise<UsersRecordFull | null>,
currentUser: UsersResponse | null,
signUp: (email: string, password: string, username: string) => Promise<UsersResponse>,
login: (email: string, password: string) => Promise<UsersResponse>,
refreshUser: () => Promise<UsersResponse | null>,
sendEmailVerification: () => Promise<void>,
confirmEmailVerification: (token: string) => Promise<void>,
confirmResetPassword: (token: string, password: string) => Promise<void>,
@ -61,13 +63,13 @@ const users = client.collection(Collections.Users);
const AuthProvider = (props: { children: ReactNode }) => {
const { children } = props;
const [currentUser, setCurrentUser] = useState<UsersRecordFull | null>(null);
const [currentUser, setCurrentUser] = useState<UsersResponse | null>(null);
const value = useMemo(() => ({
currentUser,
signUp: async (email: string, password: string, username: string) => {
try {
const user = await users.create({
const user = await users.create<UsersResponse>({
email,
password,
passwordConfirm: password,
@ -83,7 +85,7 @@ const AuthProvider = (props: { children: ReactNode }) => {
},
login: async (email: string, password: string) => {
try {
const authResponse = await users.authWithPassword(email, password);
const authResponse = await users.authWithPassword<UsersResponse>(email, password);
return Promise.resolve(authResponse.record);
} catch (error) {
return Promise.reject(new Error(formatError(error)));
@ -91,7 +93,7 @@ const AuthProvider = (props: { children: ReactNode }) => {
},
refreshUser: async () => {
try {
const authResponse = await users.authRefresh();
const authResponse = await users.authRefresh<UsersResponse>();
return Promise.resolve(authResponse.record);
} catch (error) {
client.authStore.clear();
@ -162,10 +164,10 @@ const AuthProvider = (props: { children: ReactNode }) => {
}), [currentUser]);
useEffect(() => {
setCurrentUser(client.authStore.model as UsersRecordFull | null);
setCurrentUser(client.authStore.model as UsersResponse | null);
const storeUnsubscribe = client.authStore.onChange((_token, model) => {
setCurrentUser(model as UsersRecordFull | null);
setCurrentUser(model as UsersResponse | null);
});
return () => {

View File

@ -4,17 +4,20 @@ import {
formatError,
ClientResponseError,
} from '../pocketbase';
import {
IniFilesRecordFull,
TunesRecordFull,
TunesRecordPartial,
} from '../types/dbData';
import { databaseGenericError } from '../pages/auth/notifications';
import {
Collections,
IniFilesResponse,
TunesRecord,
TunesResponse,
} from '../@types/pocketbase-types';
type Partial<T> = {
[A in keyof T]?: T[A];
};
export type TunesRecordPartial = Partial<TunesRecord>;
const tunesCollection = client.collection(Collections.Tunes);
const iniFilesCollection = client.collection(Collections.IniFiles);
@ -33,9 +36,9 @@ const useDb = () => {
const createTune = async (data: TunesRecord) => {
try {
const record = await tunesCollection.create(data);
const record = await tunesCollection.create<TunesResponse>(data);
return Promise.resolve(record as TunesRecordFull);
return Promise.resolve(record);
} catch (error) {
Sentry.captureException(error);
databaseGenericError(new Error(formatError(error)));
@ -46,14 +49,14 @@ const useDb = () => {
const getTune = async (tuneId: string) => {
try {
const tune = await tunesCollection.getFirstListItem(
const tune = await tunesCollection.getFirstListItem<TunesResponse>(
`tuneId = "${tuneId}"`,
{
expand: 'author',
},
);
return Promise.resolve(tune as TunesRecordFull);
return Promise.resolve(tune);
} catch (error) {
if ((error as ClientResponseError).isAbort) {
return Promise.reject(new Error('Cancelled'));
@ -72,9 +75,9 @@ const useDb = () => {
const getIni = async (signature: string) => {
try {
const ini = await iniFilesCollection.getFirstListItem(`signature = "${signature}"`);
const ini = await iniFilesCollection.getFirstListItem<IniFilesResponse>(`signature = "${signature}"`);
return Promise.resolve(ini as IniFilesRecordFull);
return Promise.resolve(ini);
} catch (error) {
if ((error as ClientResponseError).isAbort) {
return Promise.reject(new Error('Cancelled'));
@ -99,14 +102,14 @@ const useDb = () => {
.join(' && ');
try {
const list = await tunesCollection.getList(page, perPage, {
const list = await tunesCollection.getList<TunesResponse>(page, perPage, {
sort: '-updated',
filter,
expand: 'author',
});
return Promise.resolve({
items: list.items as TunesRecordFull[],
items: list.items,
totalItems: list.totalItems,
});
} catch (error) {
@ -123,14 +126,14 @@ const useDb = () => {
const getUserTunes = async (userId: string, page: number, perPage: number) => {
try {
const list = await tunesCollection.getList(page, perPage, {
const list = await tunesCollection.getList<TunesResponse>(page, perPage, {
sort: '-updated',
filter: `author = "${userId}"`,
expand: 'author',
});
return Promise.resolve({
items: list.items as TunesRecordFull[],
items: list.items,
totalItems: list.totalItems,
});
} catch (error) {
@ -147,11 +150,11 @@ const useDb = () => {
const autocomplete = async (attribute: string, search: string) => {
try {
const items = await tunesCollection.getFullList(10, {
const items = await tunesCollection.getFullList<TunesResponse>(10, {
filter: `${attribute} ~ "${search}"`,
});
return Promise.resolve(items as TunesRecordFull[]);
return Promise.resolve(items);
} catch (error) {
if ((error as ClientResponseError).isAbort) {
return Promise.reject(new Error('Cancelled'));
@ -166,12 +169,12 @@ const useDb = () => {
return {
updateTune: (tuneId: string, data: TunesRecordPartial): Promise<void> => updateTune(tuneId, data),
createTune: (data: TunesRecord): Promise<TunesRecordFull> => createTune(data),
getTune: (tuneId: string): Promise<TunesRecordFull | null> => getTune(tuneId),
getIni: (tuneId: string): Promise<IniFilesRecordFull | null> => getIni(tuneId),
searchTunes: (search: string, page: number, perPage: number): Promise<{ items: TunesRecordFull[]; totalItems: number }> => searchTunes(search, page, perPage),
getUserTunes: (userId: string, page: number, perPage: number): Promise<{ items: TunesRecordFull[]; totalItems: number }> => getUserTunes(userId, page, perPage),
autocomplete: (attribute: string, search: string): Promise<TunesRecordFull[]> => autocomplete(attribute, search),
createTune: (data: TunesRecord): Promise<TunesResponse> => createTune(data),
getTune: (tuneId: string): Promise<TunesResponse | null> => getTune(tuneId),
getIni: (tuneId: string): Promise<IniFilesResponse | null> => getIni(tuneId),
searchTunes: (search: string, page: number, perPage: number): Promise<{ items: TunesResponse[]; totalItems: number }> => searchTunes(search, page, perPage),
getUserTunes: (userId: string, page: number, perPage: number): Promise<{ items: TunesResponse[]; totalItems: number }> => getUserTunes(userId, page, perPage),
autocomplete: (attribute: string, search: string): Promise<TunesResponse[]> => autocomplete(attribute, search),
};
};

View File

@ -36,12 +36,12 @@ import {
isClipboardSupported,
} from '../utils/clipboard';
import { isEscape } from '../utils/keyboard/shortcuts';
import {
TunesRecordFull,
UsersRecordFull,
} from '../types/dbData';
import { formatTime } from '../utils/time';
import { useAuth } from '../contexts/AuthContext';
import {
TunesResponse,
UsersResponse,
} from '../@types/pocketbase-types';
const { useBreakpoint } = Grid;
const { Text, Title } = Typography;
@ -52,7 +52,7 @@ const Hub = () => {
const { xs } = useBreakpoint();
const { searchTunes } = useDb();
const navigate = useNavigate();
const [dataSource, setDataSource] = useState<TunesRecordFull[]>([]);
const [dataSource, setDataSource] = useState<TunesResponse[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [searchQuery, setSearchQuery] = useState('');
const [page, setPage] = useState(1);
@ -73,10 +73,10 @@ const Hub = () => {
...tune,
key: tune.tuneId,
year: tune.year,
authorUsername: (tune.expand.author as unknown as UsersRecordFull).username,
authorUsername: (tune.expand!.author as unknown as UsersResponse).username,
displacement: `${tune.displacement}l`,
aspiration: aspirationMapper[tune.aspiration],
published: formatTime(tune.updated),
updated: formatTime(tune.updated),
stars: 0,
}));
setDataSource(mapped as any);
@ -114,14 +114,14 @@ const Hub = () => {
const columns: ColumnsType<any> = [
{
title: 'Tunes',
render: (tune: TunesRecordFull) => (
render: (tune: TunesResponse) => (
<>
<Title level={5}>{tune.vehicleName}</Title>
<Space direction="vertical">
<Text type="secondary">
<Link to={generatePath(Routes.USER_ROOT, { userId: tune.author })}>
{tune.authorUsername}
</Link>, {tune.published}
{(tune as any).authorUsername}
</Link>, {tune.updated}
</Text>
<Text>{tune.engineMake}, {tune.engineCode}, {tune.displacement}, {tune.cylindersCount} cylinders, {tune.aspiration}</Text>
<Text code>{tune.signature}</Text>
@ -171,7 +171,7 @@ const Hub = () => {
dataIndex: 'authorUsername',
key: 'authorUsername',
responsive: ['sm'],
render: (userName: string, record: TunesRecordFull) => (
render: (userName: string, record: TunesResponse) => (
<Link to={generatePath(Routes.USER_ROOT, { userId: record.author })}>
{userName}
</Link>
@ -198,7 +198,7 @@ const Hub = () => {
{
dataIndex: 'tuneId',
fixed: 'right',
render: (tuneId: string, record: TunesRecordFull) => {
render: (tuneId: string, record: TunesResponse) => {
const isOwner = currentUser?.id === record.author;
const size = isOwner ? 'small' : 'middle';

View File

@ -22,7 +22,7 @@ import Loader from '../components/Loader';
import { Routes } from '../routes';
import { useAuth } from '../contexts/AuthContext';
import { formatTime } from '../utils/time';
import { UsersRecordFull } from '../types/dbData';
import { UsersResponse } from '../@types/pocketbase-types';
const { Item } = Form;
const rowProps = { gutter: 10 };
@ -71,7 +71,7 @@ const Info = ({ tuneData }: { tuneData: TuneDataState }) => {
<Row {...rowProps}>
<Col {...colProps}>
<Item>
<Input value={(tuneData.expand.author as unknown as UsersRecordFull).username} addonBefore="Author" />
<Input value={(tuneData.expand!.author as unknown as UsersResponse).username} addonBefore="Author" />
</Item>
</Col>
<Col {...colProps}>

View File

@ -56,7 +56,7 @@ import { Routes } from '../routes';
import TuneParser from '../utils/tune/TuneParser';
import TriggerLogsParser from '../utils/logs/TriggerLogsParser';
import LogValidator from '../utils/logs/LogValidator';
import useDb from '../hooks/useDb';
import useDb, { TunesRecordPartial } from '../hooks/useDb';
import useServerStorage from '../hooks/useServerStorage';
import { buildFullUrl } from '../utils/url';
import Loader from '../components/Loader';
@ -66,11 +66,10 @@ import {
} from '../utils/form';
import { aspirationMapper } from '../utils/tune/mappers';
import { copyToClipboard } from '../utils/clipboard';
import { TunesRecord } from '../@types/pocketbase-types';
import {
TunesRecordFull,
TunesRecordPartial,
} from '../types/dbData';
TunesRecord,
TunesResponse,
} from '../@types/pocketbase-types';
import { removeFilenameSuffix } from '../pocketbase';
const { Item, useForm } = Form;
@ -124,7 +123,7 @@ const UploadPage = () => {
const [isPublished, setIsPublished] = useState(false);
const [isEditMode, setIsEditMode] = useState(false);
const [readme, setReadme] = useState(defaultReadme);
const [existingTune, setExistingTune] = useState<TunesRecordFull>();
const [existingTune, setExistingTune] = useState<TunesResponse>();
const [defaultTuneFileList, setDefaultTuneFileList] = useState<UploadFile[]>([]);
const [defaultLogFilesList, setDefaultLogFilesList] = useState<UploadFile[]>([]);
@ -155,7 +154,7 @@ const UploadPage = () => {
}
const options = (await autocomplete(attribute, search))
.map((record) => record[attribute]);
.map((record) => (record as any)[attribute]);
// TODO: order by occurrence (more common - higher in the list)
const unique = [...new Set(options)].map((value) => ({ value }));

View File

@ -21,9 +21,9 @@ import { formatTime } from '../utils/time';
import useDb from '../hooks/useDb';
import { aspirationMapper } from '../utils/tune/mappers';
import {
TunesRecordFull,
UsersRecordFull,
} from '../types/dbData';
TunesResponse,
UsersResponse,
} from '../@types/pocketbase-types';
const tunePath = (tuneId: string) => generatePath(Routes.TUNE_TUNE, { tuneId });
@ -35,22 +35,22 @@ const Profile = () => {
const [pageSize, setPageSize] = useState(10);
const [total, setTotal] = useState(0);
const [isTunesLoading, setIsTunesLoading] = useState(false);
const [tunesDataSource, setTunesDataSource] = useState<TunesRecordFull[]>([]);
const [username, setUsername] = useState();
const [tunesDataSource, setTunesDataSource] = useState<TunesResponse[]>([]);
const [username, setUsername] = useState<string>();
const loadData = async () => {
setIsTunesLoading(true);
try {
const { items, totalItems } = await getUserTunes(route?.params.userId!, page, pageSize);
setTotal(totalItems);
setUsername((items[0].expand.author as UsersRecordFull).username);
setUsername((items[0]!.expand!.author as UsersResponse).username);
const mapped = items.map((tune) => ({
...tune,
key: tune.tuneId,
year: tune.year,
displacement: `${tune.displacement}l`,
aspiration: aspirationMapper[tune.aspiration],
published: formatTime(tune.updated),
updated: formatTime(tune.updated),
}));
setTunesDataSource(mapped as any);
} catch (error) {
@ -88,7 +88,7 @@ const Profile = () => {
</>}
/>
<div>
<Typography.Text italic>{tune.published}</Typography.Text>
<Typography.Text italic>{tune.updated}</Typography.Text>
</div>
</Space>
</List.Item>

View File

@ -39,7 +39,7 @@ import { usernameRules } from '../../utils/form';
import { formatTime } from '../../utils/time';
import useDb from '../../hooks/useDb';
import { aspirationMapper } from '../../utils/tune/mappers';
import { TunesRecordFull } from '../../types/dbData';
import { TunesResponse } from '../../@types/pocketbase-types';
const { Item } = Form;
@ -62,7 +62,7 @@ const Profile = () => {
const [pageSize, setPageSize] = useState(10);
const [total, setTotal] = useState(0);
const [isTunesLoading, setIsTunesLoading] = useState(false);
const [tunesDataSource, setTunesDataSource] = useState<TunesRecordFull[]>([]);
const [tunesDataSource, setTunesDataSource] = useState<TunesResponse[]>([]);
const goToEdit = (tuneId: string) => navigate(generatePath(Routes.UPLOAD_WITH_TUNE_ID, {
tuneId,
@ -106,7 +106,7 @@ const Profile = () => {
year: tune.year,
displacement: `${tune.displacement}l`,
aspiration: aspirationMapper[tune.aspiration],
published: formatTime(tune.updated),
updated: formatTime(tune.updated),
}));
setTunesDataSource(mapped as any);
} catch (error) {
@ -222,7 +222,7 @@ const Profile = () => {
</>}
/>
<div>
<Typography.Text italic>{tune.published}</Typography.Text>
<Typography.Text italic>{tune.updated}</Typography.Text>
</div>
</Space>
</List.Item>

View File

@ -1,7 +1,4 @@
import PocketBase, {
ClientResponseError,
Record,
} from 'pocketbase';
import PocketBase, { ClientResponseError } from 'pocketbase';
import { fetchEnv } from './utils/env';
const API_URL = fetchEnv('VITE_POCKETBASE_API_URL');
@ -28,5 +25,4 @@ export {
formatError,
removeFilenameSuffix,
ClientResponseError,
Record,
};

View File

@ -1,18 +0,0 @@
import { Record } from '../pocketbase';
import {
IniFilesRecord,
TunesRecord,
UsersRecord,
} from '../@types/pocketbase-types';
type Partial<T> = {
[A in keyof T]?: T[A];
};
export type TunesRecordPartial = Partial<TunesRecord>;
export interface TunesRecordFull extends TunesRecord, Record { }
export interface UsersRecordFull extends UsersRecord, Record { }
export interface IniFilesRecordFull extends IniFilesRecord, Record { }

View File

@ -3,17 +3,17 @@ import {
Logs,
TuneWithDetails,
} from '@hyper-tuner/types';
import { TunesResponse } from '../@types/pocketbase-types';
import {
CompositeLogEntry,
ToothLogEntry,
} from '../utils/logs/TriggerLogsParser';
import { TunesRecordFull } from './dbData';
export interface ConfigState extends Config {}
export interface TuneState extends TuneWithDetails {}
export interface TuneDataState extends TunesRecordFull {}
export interface TuneDataState extends TunesResponse {}
export interface LogsState {
fileName: string;