change(ui): add api client response check; add types for some immut collections

This commit is contained in:
sylenien 2022-12-26 16:29:20 +01:00
parent f1d852abb4
commit d5fc6d7a1b
14 changed files with 129 additions and 132 deletions

View file

@ -95,7 +95,16 @@ export default class APIClient {
) {
edp = `${ edp }/${ this.siteId }`
}
return fetch(edp + path, this.init);
return fetch(edp + path, this.init)
.then(response => {
if (response.ok) {
return response
} else {
throw new Error(
`! ${this.init.method} error on ${path}; ${response.status}`
)
}
})
}
get(path, params, options) {

View file

@ -145,17 +145,17 @@ function FilterAutoComplete(props: Props) {
new APIClient()
[method?.toLocaleLowerCase()](endpoint, { ...params, q: inputValue })
.then((response: any) => {
if (response.ok) {
return response.json();
}
throw new Error(response.statusText);
})
.then(({ data }: any) => {
const _options = data.map((i: any) => ({ value: i.value, label: i.value })) || [];
setOptions(_options);
callback(_options);
setLoading(false);
});
})
.catch((e) => {
throw new Error(e);
})
};
const debouncedLoadOptions = React.useCallback(debounce(loadOptions, 1000), [params]);

View file

@ -3,7 +3,6 @@ import { combineReducers } from 'redux-immutable';
import jwt from './jwt';
import user from './user';
import sessions from './sessions';
import issues from './issues';
import assignments from './assignments';
import target from './target';
import targetCustom from './targetCustom';
@ -34,11 +33,10 @@ import customMetrics from './customMetrics';
import search from './search';
import liveSearch from './liveSearch';
export default combineReducers({
const rootReducer = combineReducers({
jwt,
user,
sessions,
issues,
assignments,
target,
targetCustom,
@ -70,3 +68,7 @@ export default combineReducers({
...integrations,
...sources,
});
export type RootStore = ReturnType<typeof rootReducer>
export default rootReducer

View file

@ -21,7 +21,6 @@ const PUSH_NEW_SITE = 'user/PUSH_NEW_SITE';
const SET_ONBOARDING = 'user/SET_ONBOARDING';
const initialState = Map({
// client: Client(),
account: Account(),
siteId: null,
passwordRequestError: false,

View file

@ -1,16 +1,17 @@
import BaseService from './BaseService';
import { fetchErrorCheck } from 'App/utils'
export default class ErrorService extends BaseService {
all(params: any = {}): Promise<any[]> {
return this.client.post('/errors/search', params)
.then(fetchErrorCheck)
.then((response: { data: any; }) => response.data || []);
.then(r => r.json())
.then((response: { data: any; }) => response.data || [])
.catch(e => Promise.reject(e))
}
one(id: string): Promise<any> {
return this.client.get(`/errors/${id}`)
.then(fetchErrorCheck)
.then((response: { data: any; }) => response.data || {});
.then(r => r.json())
.then((response: { data: any; }) => response.data || {})
.catch(e => Promise.reject(e))
}
}

View file

@ -1,6 +1,5 @@
import Widget from "App/mstore/types/widget";
import APIClient from 'App/api_client';
import { fetchErrorCheck } from "App/utils";
export default class MetricService {
private client: APIClient;
@ -30,8 +29,9 @@ export default class MetricService {
*/
getMetric(metricId: string): Promise<any> {
return this.client.get('/metrics/' + metricId)
.then(fetchErrorCheck)
.then((response: { data: any; }) => response.data || {});
.then(r => r.json())
.then((response: { data: any; }) => response.data || {})
.catch(e => Promise.reject(e))
}
/**
@ -45,8 +45,9 @@ export default class MetricService {
const method = isCreating ? 'post' : 'put';
const url = isCreating ? '/metrics' : '/metrics/' + data[Widget.ID_KEY];
return this.client[method](url, data)
.then(fetchErrorCheck)
.then(r => r.json())
.then((response: { data: any; }) => response.data || {})
.catch(e => Promise.reject(e))
}
/**
@ -74,8 +75,9 @@ export default class MetricService {
getMetricChartData(metric: Widget, data: any, isWidget: boolean = false): Promise<any> {
const path = isWidget ? `/metrics/${metric.metricId}/chart` : `/metrics/try`;
return this.client.post(path, data)
.then(fetchErrorCheck)
.then((response: { data: any; }) => response.data || {});
.then(r => r.json())
.then((response: { data: any; }) => response.data || {})
.catch(e => Promise.reject(e))
}
/**

View file

@ -45,89 +45,61 @@ export interface NotesFilter {
}
export default class NotesService {
private client: APIClient;
private client: APIClient;
constructor(client?: APIClient) {
this.client = client ? client : new APIClient();
}
constructor(client?: APIClient) {
this.client = client ? client : new APIClient();
}
initClient(client?: APIClient) {
this.client = client || new APIClient();
}
initClient(client?: APIClient) {
this.client = client || new APIClient();
}
fetchNotes(filter: NotesFilter): Promise<Note[]> {
return this.client.post('/notes', filter).then(r => {
if (r.ok) {
return r.json().then(r => r.data)
} else {
throw new Error('Error getting notes: ' + r.status)
}
})
}
fetchNotes(filter: NotesFilter): Promise<Note[]> {
return this.client.post('/notes', filter).then(r => {
return r.json().then(r => r.data)
})
}
getNotesBySessionId(sessionID: string): Promise<Note[]> {
return this.client.get(`/sessions/${sessionID}/notes`)
getNotesBySessionId(sessionID: string): Promise<Note[]> {
return this.client.get(`/sessions/${sessionID}/notes`)
.then(r => {
if (r.ok) {
return r.json().then(r => r.data)
} else {
throw new Error('Error getting notes for ' +sessionID + ' cuz: ' + r.status)
}
return r.json().then(r => r.data)
})
}
}
addNote(sessionID: string, note: WriteNote): Promise<Note> {
return this.client.post(`/sessions/${sessionID}/notes`, note)
addNote(sessionID: string, note: WriteNote): Promise<Note> {
return this.client.post(`/sessions/${sessionID}/notes`, note)
.then(r => {
if (r.ok) {
return r.json().then(r => r.data)
} else {
throw new Error('Error adding note: ' + r.status)
}
return r.json().then(r => r.data)
})
}
}
updateNote(noteID: string, note: WriteNote): Promise<Note> {
return this.client.post(`/notes/${noteID}`, note)
updateNote(noteID: string, note: WriteNote): Promise<Note> {
return this.client.post(`/notes/${noteID}`, note)
.then(r => {
if (r.ok) {
return r.json().then(r => r.data)
} else {
throw new Error('Error updating note: ' + r.status)
}
return r.json().then(r => r.data)
})
}
}
deleteNote(noteID: number) {
return this.client.delete(`/notes/${noteID}`)
deleteNote(noteID: number) {
return this.client.delete(`/notes/${noteID}`)
.then(r => {
if (r.ok) {
return r.json().then(r => r.data)
} else {
throw new Error('Error deleting note: ' + r.status)
}
return r.json().then(r => r.data)
})
}
}
sendSlackNotification(noteId: string, webhook: string) {
return this.client.get(`/notes/${noteId}/slack/${webhook}`)
sendSlackNotification(noteId: string, webhook: string) {
return this.client.get(`/notes/${noteId}/slack/${webhook}`)
.then(r => {
if (r.ok) {
return r.json().then(r => r.data)
} else {
throw new Error('Error sending slack notif: ' + r.status)
}
return r.json().then(r => r.data)
})
}
}
sendMsTeamsNotification(noteId: string, webhook: string) {
return this.client.get(`/notes/${noteId}/msteams/${webhook}`)
sendMsTeamsNotification(noteId: string, webhook: string) {
return this.client.get(`/notes/${noteId}/msteams/${webhook}`)
.then(r => {
if (r.ok) {
return r.json().then(r => r.data)
} else {
throw new Error('Error sending slack notif: ' + r.status)
}
return r.json().then(r => r.data)
})
}
}
}

View file

@ -37,11 +37,7 @@ export default class RecordingsService {
reserveUrl(siteId: string, recordingData: RecordingData): Promise<{ URL: string; key: string }> {
return this.client.put(`/${siteId}/assist/save`, recordingData).then((r) => {
if (r.ok) {
return r.json().then((j) => j.data);
} else {
throw new Error("Can't reserve space for recording: " + r.status);
}
});
}
@ -51,61 +47,37 @@ export default class RecordingsService {
headers: { 'Content-Type': 'video/webm' },
body: file,
}).then((r) => {
if (r.ok) {
return true;
} else {
throw new Error("Can't upload file: " + r.status);
}
});
}
confirmFile(siteId: string, recordingData: RecordingData, key: string): Promise<any> {
return this.client.put(`/${siteId}/assist/save/done`, { ...recordingData, key }).then((r) => {
if (r.ok) {
return r.json().then((j) => j.data);
} else {
throw new Error("Can't confirm file saving: " + r.status);
}
});
}
fetchRecordings(filters: FetchFilter): Promise<IRecord[]> {
return this.client.post(`/assist/records`, filters).then((r) => {
if (r.ok) {
return r.json().then((j) => j.data);
} else {
throw new Error("Can't get recordings: " + r.status);
}
});
}
fetchRecording(id: number): Promise<IRecord> {
return this.client.get(`/assist/records/${id}`).then((r) => {
if (r.ok) {
return r.json().then((j) => j.data);
} else {
throw new Error("Can't get recordings: " + r.status);
}
});
}
updateRecordingName(id: number, name: string): Promise<IRecord> {
return this.client.post(`/assist/records/${id}`, { name }).then((r) => {
if (r.ok) {
return r.json().then((j) => j.data);
} else {
throw new Error("Can't get recordings: " + r.status);
}
});
}
deleteRecording(id: number): Promise<any> {
return this.client.delete(`/assist/records/${id}`).then((r) => {
if (r.ok) {
return r.json().then((j) => j.data);
} else {
throw new Error("Can't get recordings: " + r.status);
}
});
}
}

View file

@ -1,5 +1,4 @@
import APIClient from 'App/api_client';
import { fetchErrorCheck } from 'App/utils';
export default class SettingsService {
private client: APIClient;
@ -26,8 +25,9 @@ export default class SettingsService {
getSessions(filter: any) {
return this.client
.post('/sessions/search', filter)
.then(fetchErrorCheck)
.then((response) => response.data || []);
.then(r => r.json())
.then((response) => response.data || [])
.catch(e => Promise.reject(e))
}
getSessionInfo(sessionId: string, isLive?: boolean): Promise<Record<string, any>> {
@ -41,7 +41,8 @@ export default class SettingsService {
getLiveSessions(filter: any) {
return this.client
.post('/assist/sessions', filter)
.then(fetchErrorCheck)
.then((response) => response.data || []);
.then(r => r.json())
.then((response) => response.data || [])
.catch(e => Promise.reject(e))
}
}

View file

@ -1,6 +1,5 @@
import APIClient from 'App/api_client';
import { IUser } from 'App/mstore/types/user'
import { fetchErrorCheck } from 'App/utils'
export default class UserService {
private client: APIClient;
@ -29,12 +28,14 @@ export default class UserService {
const data = user.toSave();
if (user.userId) {
return this.client.put('/client/members/' + user.userId, data)
.then(fetchErrorCheck)
.then(r => r.json())
.then((response: { data: any; }) => response.data || {})
.catch(e => Promise.reject(e))
} else {
return this.client.post('/client/members', data)
.then(fetchErrorCheck)
.then((response: { data: any; }) => response.data || {});
.then(r => r.json())
.then((response: { data: any; }) => response.data || {})
.catch(e => Promise.reject(e))
}
}
@ -46,8 +47,9 @@ export default class UserService {
delete(userId: string) {
return this.client.delete('/client/members/' + userId)
.then(fetchErrorCheck)
.then((response: { data: any; }) => response.data || {});
.then(r => r.json())
.then((response: { data: any; }) => response.data || {})
.catch(e => Promise.reject(e))
}
getRoles() {

View file

@ -1,7 +1,27 @@
import Member from 'Types/member';
import Limit from './limit';
import Member, { IMember } from 'Types/member';
import Limit, { ILimits } from './limit';
import { DateTime } from 'luxon';
// TODO types for mobx and all
export interface IAccount extends IMember {
changePassword?: any
limits: ILimits
banner: string
email: string
verifiedEmail: string
id: string
smtp: boolean
license: string
expirationDate?: DateTime
permissions: string[]
iceServers: string
hasPassword: boolean
apiKey: string
tenantKey: string
edition: string
optOut: string
}
export default Member.extend({
changePassword: undefined,
limits: Limit(),

View file

@ -1,6 +1,16 @@
import Record from 'Types/Record';
import { Map } from 'immutable';
interface ILimitValue {
limit: number
remaining: number
}
export interface ILimits {
teamMember: ILimitValue
sites: ILimitValue
}
const defaultValues = Map({ limit: 0, remaining: 0 });
const Limit = Record({
teamMember: defaultValues,

View file

@ -2,6 +2,20 @@ import Record from 'Types/Record';
import { DateTime } from 'luxon';
import { validateEmail, validateName } from 'App/validate';
export interface IMember {
id: string
name: string
email: string
createdAt: DateTime
admin: boolean
superAdmin: boolean
joined: boolean
expiredInvitation: boolean
roleId: string
roleName: string
invitationLink: string
}
export default Record({
id: undefined,
name: '',

View file

@ -346,13 +346,6 @@ export const exportCSVFile = (headers, items, fileTitle) => {
}
};
export const fetchErrorCheck = async (response: any) => {
if (!response.ok) {
return Promise.reject(response);
}
return response.json();
};
export const cleanSessionFilters = (data: any) => {
const { filters, ...rest } = data;
const _fitlers = filters.filter((f: any) => {