Merge branch 'dev' into clickmap-fix
This commit is contained in:
commit
368159aed3
24 changed files with 83 additions and 110 deletions
|
|
@ -25,24 +25,24 @@ def __get_autocomplete_table(value, project_id):
|
|||
if e == schemas.FilterType.user_country:
|
||||
c_list = countries.get_country_code_autocomplete(value)
|
||||
if len(c_list) > 0:
|
||||
sub_queries.append(f"""(SELECT DISTINCT ON(value) type, value
|
||||
sub_queries.append(f"""(SELECT DISTINCT ON(value) '{e.value}' AS _type, value
|
||||
FROM {TABLE}
|
||||
WHERE project_id = %(project_id)s
|
||||
AND type= '{e}'
|
||||
AND type= '{e.value.upper()}'
|
||||
AND value IN %(c_list)s)""")
|
||||
continue
|
||||
sub_queries.append(f"""(SELECT type, value
|
||||
sub_queries.append(f"""(SELECT '{e.value}' AS _type, value
|
||||
FROM {TABLE}
|
||||
WHERE project_id = %(project_id)s
|
||||
AND type= '{e}'
|
||||
AND type= '{e.value.upper()}'
|
||||
AND value ILIKE %(svalue)s
|
||||
ORDER BY value
|
||||
LIMIT 5)""")
|
||||
if len(value) > 2:
|
||||
sub_queries.append(f"""(SELECT type, value
|
||||
sub_queries.append(f"""(SELECT '{e.value}' AS _type, value
|
||||
FROM {TABLE}
|
||||
WHERE project_id = %(project_id)s
|
||||
AND type= '{e}'
|
||||
AND type= '{e.value.upper()}'
|
||||
AND value ILIKE %(value)s
|
||||
ORDER BY value
|
||||
LIMIT 5)""")
|
||||
|
|
@ -62,8 +62,11 @@ def __get_autocomplete_table(value, project_id):
|
|||
print(value)
|
||||
print("--------------------")
|
||||
raise err
|
||||
results = helper.list_to_camel_case(cur.fetchall())
|
||||
return results
|
||||
results = cur.fetchall()
|
||||
for r in results:
|
||||
r["type"] = r.pop("_type")
|
||||
results = helper.list_to_camel_case(results)
|
||||
return results
|
||||
|
||||
|
||||
def __generic_query(typename, value_length=None):
|
||||
|
|
|
|||
|
|
@ -25,24 +25,24 @@ def __get_autocomplete_table(value, project_id):
|
|||
if e == schemas.FilterType.user_country:
|
||||
c_list = countries.get_country_code_autocomplete(value)
|
||||
if len(c_list) > 0:
|
||||
sub_queries.append(f"""(SELECT DISTINCT ON(value) type, value
|
||||
sub_queries.append(f"""(SELECT DISTINCT ON(value) '{e.value}' AS _type, value
|
||||
FROM {TABLE}
|
||||
WHERE project_id = %(project_id)s
|
||||
AND type= '{e}'
|
||||
AND type= '{e.value.upper()}'
|
||||
AND value IN %(c_list)s)""")
|
||||
continue
|
||||
sub_queries.append(f"""(SELECT type, value
|
||||
sub_queries.append(f"""(SELECT '{e.value}' AS _type, value
|
||||
FROM {TABLE}
|
||||
WHERE project_id = %(project_id)s
|
||||
AND type= '{e}'
|
||||
AND type= '{e.value.upper()}'
|
||||
AND value ILIKE %(svalue)s
|
||||
ORDER BY value
|
||||
LIMIT 5)""")
|
||||
if len(value) > 2:
|
||||
sub_queries.append(f"""(SELECT type, value
|
||||
sub_queries.append(f"""(SELECT '{e.value}' AS _type, value
|
||||
FROM {TABLE}
|
||||
WHERE project_id = %(project_id)s
|
||||
AND type= '{e}'
|
||||
AND type= '{e.value.upper()}'
|
||||
AND value ILIKE %(value)s
|
||||
ORDER BY value
|
||||
LIMIT 5)""")
|
||||
|
|
@ -64,7 +64,10 @@ def __get_autocomplete_table(value, project_id):
|
|||
print(value)
|
||||
print("--------------------")
|
||||
raise err
|
||||
return results
|
||||
for r in results:
|
||||
r["type"] = r.pop("_type")
|
||||
results = helper.list_to_camel_case(results)
|
||||
return results
|
||||
|
||||
|
||||
def __generic_query(typename, value_length=None):
|
||||
|
|
|
|||
|
|
@ -95,13 +95,11 @@ export default class APIClient {
|
|||
edp = `${ edp }/${ this.siteId }`
|
||||
}
|
||||
return fetch(edp + path, this.init)
|
||||
.then(response => {
|
||||
.then((response) => {
|
||||
if (response.ok) {
|
||||
return response
|
||||
} else {
|
||||
throw new Error(
|
||||
`! ${this.init.method} error on ${path}; ${response.status}`
|
||||
)
|
||||
return Promise.reject({ message: `! ${this.init.method} error on ${path}; ${response.status}`, response });
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,9 +33,10 @@ export default () => (next) => (action) => {
|
|||
next({ type: UPDATE_JWT, data: jwt });
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
.catch(async (e) => {
|
||||
const data = await e.response.json();
|
||||
logger.error('Error during API request. ', e);
|
||||
return next({ type: FAILURE, errors: parseError(e) });
|
||||
return next({ type: FAILURE, errors: parseError(data.errors) });
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -39,17 +39,6 @@ class CustomFieldForm extends React.PureComponent {
|
|||
placeholder="Field Name"
|
||||
/>
|
||||
</Form.Field>
|
||||
|
||||
{/* TODO: errors state is not updating properly */}
|
||||
{/* {errors && (
|
||||
<div className="mb-3">
|
||||
{errors.map((error, i) => (
|
||||
<Message visible={errors} size="mini" error key={i} className={styles.error}>
|
||||
{error.message}
|
||||
</Message>
|
||||
))}
|
||||
</div>
|
||||
)} */}
|
||||
|
||||
<div className="flex justify-between">
|
||||
<div className="flex items-center">
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import ListItem from './ListItem';
|
|||
import { confirm } from 'UI';
|
||||
import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
|
||||
import { useModal } from 'App/components/Modal';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
function CustomFields(props) {
|
||||
const [currentSite, setCurrentSite] = React.useState(props.sites.get(0));
|
||||
|
|
@ -25,10 +26,11 @@ function CustomFields(props) {
|
|||
}, []);
|
||||
|
||||
const save = (field) => {
|
||||
props.save(currentSite.id, field).then(() => {
|
||||
const { errors } = props;
|
||||
if (!errors || errors.size === 0) {
|
||||
props.save(currentSite.id, field).then((response) => {
|
||||
if (!response || !response.errors || response.errors.size === 0) {
|
||||
hideModal();
|
||||
} else {
|
||||
toast.error(response.errors[0]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
@ -73,7 +75,7 @@ function CustomFields(props) {
|
|||
</div>
|
||||
<div className="ml-auto">
|
||||
<Tooltip title="You've reached the limit of 10 metadata." disabled={fields.size < 10}>
|
||||
<Button disabled={fields.size >= 10} variant="primary" onClick={() => init()}>Add Metadata</Button>
|
||||
<Button disabled={fields.size >= 10} variant="primary" onClick={() => init()}>Add Metadata</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ function Integrations(props: Props) {
|
|||
}, []);
|
||||
|
||||
const onClick = (integration: any, width: number) => {
|
||||
if (integration.slug) {
|
||||
if (integration.slug && integration.slug !== 'slack' && integration.slug !== 'msteams') {
|
||||
props.fetch(integration.slug, props.siteId);
|
||||
}
|
||||
|
||||
|
|
@ -241,30 +241,15 @@ const integrations = [
|
|||
description:
|
||||
"Reproduce issues as if they happened in your own browser. Plugins help capture your application's store, HTTP requeets, GraphQL queries, and more.",
|
||||
integrations: [
|
||||
{ title: 'Redux', slug: 'redux', icon: 'integrations/redux', component: <ReduxDoc /> },
|
||||
{ title: 'VueX', slug: 'vuex', icon: 'integrations/vuejs', component: <VueDoc /> },
|
||||
{ title: 'Pinia', slug: 'pinia', icon: 'integrations/pinia', component: <PiniaDoc /> },
|
||||
{
|
||||
title: 'GraphQL',
|
||||
slug: 'graphql',
|
||||
icon: 'integrations/graphql',
|
||||
component: <GraphQLDoc />,
|
||||
},
|
||||
{ title: 'NgRx', slug: 'ngrx', icon: 'integrations/ngrx', component: <NgRxDoc /> },
|
||||
{ title: 'MobX', slug: 'mobx', icon: 'integrations/mobx', component: <MobxDoc /> },
|
||||
{
|
||||
title: 'Profiler',
|
||||
slug: 'profiler',
|
||||
icon: 'integrations/openreplay',
|
||||
component: <ProfilerDoc />,
|
||||
},
|
||||
{
|
||||
title: 'Assist',
|
||||
slug: 'assist',
|
||||
icon: 'integrations/openreplay',
|
||||
component: <AssistDoc />,
|
||||
},
|
||||
{ title: 'Zustand', slug: 'zustand', icon: '', header: '🐻', component: <ZustandDoc /> },
|
||||
{ title: 'Redux', icon: 'integrations/redux', component: <ReduxDoc /> },
|
||||
{ title: 'VueX', icon: 'integrations/vuejs', component: <VueDoc /> },
|
||||
{ title: 'Pinia', icon: 'integrations/pinia', component: <PiniaDoc /> },
|
||||
{ title: 'GraphQL', icon: 'integrations/graphql', component: <GraphQLDoc /> },
|
||||
{ title: 'NgRx', icon: 'integrations/ngrx', component: <NgRxDoc /> },
|
||||
{ title: 'MobX', icon: 'integrations/mobx', component: <MobxDoc /> },
|
||||
{ title: 'Profiler', icon: 'integrations/openreplay', component: <ProfilerDoc /> },
|
||||
{ title: 'Assist', icon: 'integrations/openreplay', component: <AssistDoc /> },
|
||||
{ title: 'Zustand', icon: '', header: '🐻', component: <ZustandDoc /> },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { connect } from 'react-redux';
|
|||
import { Button, Message, Form, Input } from 'UI';
|
||||
import styles from './profileSettings.module.css';
|
||||
import { updatePassword } from 'Duck/user';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
const ERROR_DOESNT_MATCH = "Passwords doesn't match";
|
||||
const MIN_LENGTH = 8;
|
||||
|
|
@ -48,12 +49,15 @@ export default class ChangePassword extends React.PureComponent {
|
|||
oldPassword,
|
||||
newPassword,
|
||||
})
|
||||
.then(() => {
|
||||
if (this.props.passwordErrors.size === 0) {
|
||||
this.setState({
|
||||
...defaultState,
|
||||
success: true,
|
||||
});
|
||||
.then((e) => {
|
||||
const success = !e || !e.errors || e.errors.length === 0;
|
||||
this.setState({
|
||||
...defaultState,
|
||||
success: success,
|
||||
show: !success
|
||||
});
|
||||
if (success) {
|
||||
toast.success(`Successfully changed password`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
@ -98,7 +102,7 @@ export default class ChangePassword extends React.PureComponent {
|
|||
<Message error hidden={!doesntMatch}>
|
||||
{ERROR_DOESNT_MATCH}
|
||||
</Message>
|
||||
<div className="flex items-center">
|
||||
<div className="flex items-center pt-3">
|
||||
<Button type="submit" variant="outline" disabled={this.isSubmitDisabled()} loading={loading}>
|
||||
Change Password
|
||||
</Button>
|
||||
|
|
@ -107,9 +111,6 @@ export default class ChangePassword extends React.PureComponent {
|
|||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
<Message success hidden={!success}>
|
||||
{'Successfully changed the password!'}
|
||||
</Message>
|
||||
</Form>
|
||||
) : (
|
||||
<div onClick={() => this.setState({ show: true })}>
|
||||
|
|
|
|||
|
|
@ -88,7 +88,6 @@ class EventGroupWrapper extends React.Component {
|
|||
)}
|
||||
{isNote ? (
|
||||
<NoteEvent
|
||||
userEmail={this.props.members.find((m) => m.id === event.userId)?.email || event.userId}
|
||||
note={event}
|
||||
filterOutNote={filterOutNote}
|
||||
onEdit={this.props.setEditNoteTooltip}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import { TeamBadge } from 'Shared/SessionListContainer/components/Notes';
|
|||
interface Props {
|
||||
note: Note;
|
||||
noEdit: boolean;
|
||||
userEmail: string;
|
||||
filterOutNote: (id: number) => void;
|
||||
onEdit: (noteTooltipObj: Record<string, any>) => void;
|
||||
}
|
||||
|
|
@ -86,7 +85,7 @@ function NoteEvent(props: Props) {
|
|||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
{props.userEmail}, {props.userEmail}
|
||||
{props.note.userName}
|
||||
</div>
|
||||
<div className="text-disabled-text text-sm">
|
||||
{formatTimeOrDate(props.note.createdAt as unknown as number, timezone)}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import withLocationHandlers from 'HOCs/withLocationHandlers';
|
|||
import { useStore } from 'App/mstore';
|
||||
import PlayerBlockHeader from './Player/ReplayPlayer/PlayerBlockHeader';
|
||||
import ReadNote from '../Session_/Player/Controls/components/ReadNote';
|
||||
import { fetchList as fetchMembers } from 'Duck/member';
|
||||
import PlayerContent from './Player/ReplayPlayer/PlayerContent';
|
||||
import { IPlayerContext, PlayerContext, defaultContextValue } from './playerContext';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
|
|
@ -47,8 +46,6 @@ function WebPlayer(props: any) {
|
|||
);
|
||||
setContextValue({ player: WebPlayerInst, store: PlayerStore });
|
||||
|
||||
props.fetchMembers();
|
||||
|
||||
notesStore.fetchSessionNotes(session.sessionId).then((r) => {
|
||||
const note = props.query.get('note');
|
||||
if (note) {
|
||||
|
|
@ -58,7 +55,6 @@ function WebPlayer(props: any) {
|
|||
}
|
||||
})
|
||||
|
||||
|
||||
const jumpToTime = props.query.get('jumpto');
|
||||
const freeze = props.query.get('freeze')
|
||||
if (jumpToTime) {
|
||||
|
|
@ -112,10 +108,6 @@ function WebPlayer(props: any) {
|
|||
<Modal open={showNoteModal} onClose={onNoteClose}>
|
||||
{showNoteModal ? (
|
||||
<ReadNote
|
||||
userEmail={
|
||||
props.members.find((m: Record<string, any>) => m.id === noteItem?.userId)?.email
|
||||
|| ''
|
||||
}
|
||||
note={noteItem}
|
||||
onClose={onNoteClose}
|
||||
notFound={!noteItem}
|
||||
|
|
@ -140,6 +132,5 @@ export default connect(
|
|||
toggleFullscreen,
|
||||
closeBottomBlock,
|
||||
fetchList,
|
||||
fetchMembers,
|
||||
}
|
||||
)(withLocationHandlers()(observer(WebPlayer)));
|
||||
|
|
|
|||
|
|
@ -46,6 +46,12 @@ function Steps({ xrayProps, notes, members }: Props) {
|
|||
bugReportStore.resetSteps();
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
if (bugReportStore.sessionEventSteps.length < RADIUS && bugReportStore.sessionEventSteps.length > 0) {
|
||||
setRadius(bugReportStore.sessionEventSteps.length);
|
||||
}
|
||||
}, [bugReportStore.sessionEventSteps])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<SectionTitle>Steps to reproduce</SectionTitle>
|
||||
|
|
@ -63,7 +69,7 @@ function Steps({ xrayProps, notes, members }: Props) {
|
|||
STEPS
|
||||
<div id="pdf-ignore">
|
||||
{timePointer > 0 ? (
|
||||
<StepRadius pickRadius={stepPickRadius} setRadius={setRadius} />
|
||||
<StepRadius pickRadius={stepPickRadius} setRadius={setRadius} stepsNum={bugReportStore.sessionEventSteps.length}/>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,9 +4,10 @@ import { Tooltip } from 'UI'
|
|||
interface Props {
|
||||
pickRadius: number;
|
||||
setRadius: (v: number) => void;
|
||||
stepsNum: number;
|
||||
}
|
||||
|
||||
function StepRadius({ pickRadius, setRadius }: Props) {
|
||||
function StepRadius({ pickRadius, setRadius, stepsNum }: Props) {
|
||||
return (
|
||||
<div className="w-full flex items-center gap-4">
|
||||
<div className="border-b border-dotted border-gray-medium cursor-help">
|
||||
|
|
@ -18,7 +19,7 @@ function StepRadius({ pickRadius, setRadius }: Props) {
|
|||
<div className="flex items-center gap-1">
|
||||
<div
|
||||
className="rounded px-2 bg-light-blue-bg cursor-pointer hover:bg-teal-light"
|
||||
onClick={() => setRadius(pickRadius + 1)}
|
||||
onClick={() => pickRadius < Math.floor(stepsNum/2) ? setRadius(pickRadius + 1) : null}
|
||||
>
|
||||
+1
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ export function getClosestEventStep(time: number, arr: Step[]) {
|
|||
export const selectEventSteps = (steps: Step[], targetTime: number, radius: number) => {
|
||||
const { targetStep, index } = getClosestEventStep(targetTime, steps)
|
||||
|
||||
const stepsBeforeEvent = steps.slice(index - radius, index)
|
||||
const stepsBeforeEvent = steps.slice(Math.max(index - radius, 0), index)
|
||||
const stepsAfterEvent = steps.slice(index + 1, index + 1 + radius)
|
||||
|
||||
return [...stepsBeforeEvent, targetStep, ...stepsAfterEvent]
|
||||
|
|
|
|||
|
|
@ -88,7 +88,6 @@ class EventGroupWrapper extends React.Component {
|
|||
)}
|
||||
{isNote ? (
|
||||
<NoteEvent
|
||||
userEmail={this.props.members.find((m) => m.id === event.userId)?.email || event.userId}
|
||||
note={event}
|
||||
filterOutNote={filterOutNote}
|
||||
onEdit={this.props.setEditNoteTooltip}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import { TeamBadge } from 'Shared/SessionListContainer/components/Notes';
|
|||
interface Props {
|
||||
note: Note;
|
||||
noEdit: boolean;
|
||||
userEmail: string;
|
||||
filterOutNote: (id: number) => void;
|
||||
onEdit: (noteTooltipObj: Record<string, any>) => void;
|
||||
}
|
||||
|
|
@ -86,7 +85,7 @@ function NoteEvent(props: Props) {
|
|||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
{props.userEmail}, {props.userEmail}
|
||||
{props.note.userName}
|
||||
</div>
|
||||
<div className="text-disabled-text text-sm">
|
||||
{formatTimeOrDate(props.note.createdAt as unknown as number, timezone)}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ function ReadNote(props: Props) {
|
|||
<Icon name="quotes" color="main" size={16} />
|
||||
</div>
|
||||
<div className="ml-2">
|
||||
<div className="text-base">{props.userEmail}</div>
|
||||
<div className="text-base">{props.note.userName}</div>
|
||||
<div className="text-disabled-text text-sm">
|
||||
{formatTimeOrDate(props.note.createdAt as unknown as number, timezone)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -15,9 +15,6 @@ function SessionListContainer({
|
|||
fetchMembers: () => void;
|
||||
members: object[];
|
||||
}) {
|
||||
React.useEffect(() => {
|
||||
fetchMembers();
|
||||
}, []);
|
||||
return (
|
||||
<div className="widget-wrapper">
|
||||
<SessionHeader />
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import TeamBadge from './TeamBadge';
|
|||
|
||||
interface Props {
|
||||
note: Note;
|
||||
userEmail: string;
|
||||
}
|
||||
|
||||
function NoteItem(props: Props) {
|
||||
|
|
@ -69,7 +68,7 @@ function NoteItem(props: Props) {
|
|||
) : null}
|
||||
<div className="text-disabled-text flex items-center text-sm">
|
||||
<span className="color-gray-darkest mr-1">By </span>
|
||||
{props.userEmail},{' '}
|
||||
{props.note.userName},{' '}
|
||||
{formatTimeOrDate(props.note.createdAt as unknown as number, timezone)}
|
||||
<div className="mx-2" />
|
||||
{!props.note.isPublic ? null : <TeamBadge />}
|
||||
|
|
|
|||
|
|
@ -35,10 +35,7 @@ function NotesList({ members }: { members: Array<Record<string, any>> }) {
|
|||
<div className="border-b rounded bg-white">
|
||||
{sliceListPerPage(list, notesStore.page - 1, notesStore.pageSize).map((note) => (
|
||||
<React.Fragment key={note.noteId}>
|
||||
<NoteItem
|
||||
note={note}
|
||||
userEmail={members.find((m) => m.id === note.userId)?.email || note.userId}
|
||||
/>
|
||||
<NoteItem note={note} />
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -91,15 +91,13 @@ export default class SharePopup extends React.PureComponent {
|
|||
const { trigger, channels, msTeamsChannels, showCopyLink = false } = this.props;
|
||||
const { comment, channelId, teamsChannel, loading } = this.state;
|
||||
|
||||
// const slackOptions = channels
|
||||
// .map(({ webhookId, name }) => ({ value: webhookId, label: name }))
|
||||
// .toJS();
|
||||
const slackOptions = channels
|
||||
.map(({ webhookId, name }) => ({ value: webhookId, label: name }))
|
||||
.toJS();
|
||||
|
||||
// const msTeamsOptions = msTeamsChannels
|
||||
// .map(({ webhookId, name }) => ({ value: webhookId, label: name }))
|
||||
// .toJS();
|
||||
|
||||
const slackOptions = [], msTeamsOptions = [];
|
||||
const msTeamsOptions = msTeamsChannels
|
||||
.map(({ webhookId, name }) => ({ value: webhookId, label: name }))
|
||||
.toJS();
|
||||
|
||||
return (
|
||||
<Popover
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ const reducer = (state = initialState, action = {}) => {
|
|||
case RESET_PASSWORD.SUCCESS:
|
||||
case UPDATE_PASSWORD.SUCCESS:
|
||||
case LOGIN.SUCCESS:
|
||||
state.set('account', Account({...action.data.user })).set('loginRequest', { loading: false, errors: [] })
|
||||
state.set('account', Account({...action.data.user })).set('loginRequest', { loading: false, errors: [] }).set('passwordErrors', List())
|
||||
case SIGNUP.SUCCESS:
|
||||
state.set('account', Account(action.data.user)).set('onboarding', true);
|
||||
case REQUEST_RESET_PASSWORD.SUCCESS:
|
||||
|
|
|
|||
|
|
@ -71,11 +71,16 @@ export default class SettingsStore {
|
|||
return webhookService.saveWebhook(inst)
|
||||
.then(data => {
|
||||
this.webhookInst = new Webhook(data)
|
||||
this.webhooks = [...this.webhooks, this.webhookInst]
|
||||
if (inst.webhookId === undefined) this.setWebhooks([...this.webhooks, this.webhookInst])
|
||||
else this.setWebhooks([...this.webhooks.filter(hook => hook.webhookId !== data.webhookId), this.webhookInst])
|
||||
this.hooksLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
setWebhooks = (webhooks: Webhook[]) => {
|
||||
this.webhooks = webhooks
|
||||
}
|
||||
|
||||
removeWebhook = (hookId: string) => {
|
||||
this.hooksLoading = true
|
||||
return webhookService.removeWebhook(hookId)
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ export interface Note {
|
|||
tag: iTag
|
||||
timestamp: number
|
||||
userId: number
|
||||
userName: string
|
||||
}
|
||||
|
||||
export interface NotesFilter {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue