Skip to content

Commit

Permalink
fix: only apply throttle on lu/lg update handler (#2823)
Browse files Browse the repository at this point in the history
* only apply throttle on lu/lg `update` handler

* fix ts type validation

* apply addLgTemplate

Co-authored-by: Andy Brown <asbrown002@gmail.com>
  • Loading branch information
yeze322 and a-b-r-o-w-n authored Apr 30, 2020
1 parent f486808 commit 4767c24
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 118 deletions.
140 changes: 73 additions & 67 deletions Composer/packages/client/src/shell/lgApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import { useContext, useEffect, useState } from 'react';
import { LgFile } from '@bfc/shared';
import throttle from 'lodash/throttle';
import mapValues from 'lodash/mapValues';

import * as lgUtil from '../utils/lgUtil';
import { State, BoundActionHandlers } from '../store/types';
Expand All @@ -13,76 +12,81 @@ import { StoreContext } from '../store';
const createThrottledFunc = fn => throttle(fn, 1000, { leading: true, trailing: true });

function createLgApi(state: State, actions: BoundActionHandlers, lgFileResolver: (id: string) => LgFile | undefined) {
const api = {
getLgTemplates: id => {
if (id === undefined) throw new Error('must have a file id');
const focusedDialogId = state.focusPath.split('#').shift() || id;
const file = lgFileResolver(focusedDialogId);
if (!file) throw new Error(`lg file ${id} not found`);
return file.templates;
},

updateLgTemplate: async (id: string, templateName: string, templateBody: string) => {
const file = lgFileResolver(id);
if (!file) throw new Error(`lg file ${id} not found`);
if (!templateName) throw new Error(`templateName is missing or empty`);
const template = { name: templateName, body: templateBody, parameters: [] };

const projectId = state.projectId;

lgUtil.checkSingleLgTemplate(template);

await actions.updateLgTemplate({
file,
projectId,
templateName,
template,
});
},
const getLgTemplates = id => {
if (id === undefined) throw new Error('must have a file id');
const focusedDialogId = state.focusPath.split('#').shift() || id;
const file = lgFileResolver(focusedDialogId);
if (!file) throw new Error(`lg file ${id} not found`);
return file.templates;
};

copyLgTemplate: async (id, fromTemplateName, toTemplateName) => {
const file = lgFileResolver(id);
if (!file) throw new Error(`lg file ${id} not found`);
if (!fromTemplateName || !toTemplateName) throw new Error(`templateName is missing or empty`);
const updateLgTemplate = async (id: string, templateName: string, templateBody: string) => {
const file = lgFileResolver(id);
if (!file) throw new Error(`lg file ${id} not found`);
if (!templateName) throw new Error(`templateName is missing or empty`);
const template = { name: templateName, body: templateBody, parameters: [] };

const projectId = state.projectId;
const projectId = state.projectId;

return actions.copyLgTemplate({
file,
projectId,
fromTemplateName,
toTemplateName,
});
},

removeLgTemplate: async (id, templateName) => {
const file = lgFileResolver(id);
if (!file) throw new Error(`lg file ${id} not found`);
if (!templateName) throw new Error(`templateName is missing or empty`);
const projectId = state.projectId;

return actions.removeLgTemplate({
file,
projectId,
templateName,
});
},

removeLgTemplates: async (id, templateNames) => {
const file = lgFileResolver(id);
if (!file) throw new Error(`lg file ${id} not found`);
if (!templateNames) throw new Error(`templateName is missing or empty`);
const projectId = state.projectId;

return actions.removeLgTemplates({
file,
projectId,
templateNames,
});
},
lgUtil.checkSingleLgTemplate(template);

await actions.updateLgTemplate({
file,
projectId,
templateName,
template,
});
};

return mapValues(api, fn => createThrottledFunc(fn));
const copyLgTemplate = async (id, fromTemplateName, toTemplateName) => {
const file = lgFileResolver(id);
if (!file) throw new Error(`lg file ${id} not found`);
if (!fromTemplateName || !toTemplateName) throw new Error(`templateName is missing or empty`);

const projectId = state.projectId;

return actions.copyLgTemplate({
file,
projectId,
fromTemplateName,
toTemplateName,
});
};

const removeLgTemplate = async (id, templateName) => {
const file = lgFileResolver(id);
if (!file) throw new Error(`lg file ${id} not found`);
if (!templateName) throw new Error(`templateName is missing or empty`);
const projectId = state.projectId;

return actions.removeLgTemplate({
file,
projectId,
templateName,
});
};

const removeLgTemplates = async (id, templateNames) => {
const file = lgFileResolver(id);
if (!file) throw new Error(`lg file ${id} not found`);
if (!templateNames) throw new Error(`templateName is missing or empty`);
const projectId = state.projectId;

return actions.removeLgTemplates({
file,
projectId,
templateNames,
});
};

return {
addLgTemplate: updateLgTemplate,
getLgTemplates,
updateLgTemplate: createThrottledFunc(updateLgTemplate),
removeLgTemplate,
removeLgTemplates,
copyLgTemplate,
};
}

export function useLgApi() {
Expand All @@ -97,7 +101,9 @@ export function useLgApi() {

return () => {
Object.keys(newApi).forEach(apiName => {
newApi[apiName].flush();
if (typeof newApi[apiName].flush === 'function') {
newApi[apiName].flush();
}
});
};
}, [projectId, focusPath]);
Expand Down
100 changes: 53 additions & 47 deletions Composer/packages/client/src/shell/luApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,61 +4,65 @@
import { useContext, useEffect, useState } from 'react';
import { LuFile, LuIntentSection } from '@bfc/shared';
import throttle from 'lodash/throttle';
import mapValues from 'lodash/mapValues';

import * as luUtil from '../utils/luUtil';
import { State, BoundActionHandlers } from '../store/types';
import { StoreContext } from '../store';

const createThrottledFunc = fn => throttle(fn, 0, { leading: true, trailing: true });
const createThrottledFunc = fn => throttle(fn, 1000, { leading: true, trailing: true });

function createLuApi(state: State, actions: BoundActionHandlers, luFileResolver: (id: string) => LuFile | undefined) {
const api = {
addLuIntent: async (id: string, intentName: string, intent: LuIntentSection) => {
const file = luFileResolver(id);
if (!file) throw new Error(`lu file ${id} not found`);
if (!intentName) throw new Error(`intentName is missing or empty`);

const content = luUtil.addIntent(file.content, intent);
const projectId = state.projectId;
return await actions.updateLuFile({ id: file.id, projectId, content });
},
updateLuIntent: async (id: string, intentName: string, intent: LuIntentSection) => {
const file = luFileResolver(id);
if (!file) throw new Error(`lu file ${id} not found`);
if (!intentName) throw new Error(`intentName is missing or empty`);

const content = luUtil.updateIntent(file.content, intentName, intent);
const projectId = state.projectId;
return await actions.updateLuFile({ id: file.id, projectId, content });
},

removeLuIntent: async (id: string, intentName: string) => {
const file = luFileResolver(id);
if (!file) throw new Error(`lu file ${id} not found`);
if (!intentName) throw new Error(`intentName is missing or empty`);

const content = luUtil.removeIntent(file.content, intentName);
const projectId = state.projectId;
return await actions.updateLuFile({ id: file.id, projectId, content });
},

getLuIntents: (id: string): LuIntentSection[] => {
if (id === undefined) throw new Error('must have a file id');
const focusedDialogId = state.focusPath.split('#').shift() || id;
const file = luFileResolver(focusedDialogId);
if (!file) throw new Error(`lu file ${id} not found`);
return file.intents;
},

getLuIntent: (id: string, intentName: string): LuIntentSection | undefined => {
const file = luFileResolver(id);
if (!file) throw new Error(`lu file ${id} not found`);
return file.intents.find(({ Name }) => Name === intentName);
},
const addLuIntent = async (id: string, intentName: string, intent: LuIntentSection) => {
const file = luFileResolver(id);
if (!file) throw new Error(`lu file ${id} not found`);
if (!intentName) throw new Error(`intentName is missing or empty`);

const content = luUtil.addIntent(file.content, intent);
const projectId = state.projectId;
return await actions.updateLuFile({ id: file.id, projectId, content });
};

const updateLuIntent = async (id: string, intentName: string, intent: LuIntentSection) => {
const file = luFileResolver(id);
if (!file) throw new Error(`lu file ${id} not found`);
if (!intentName) throw new Error(`intentName is missing or empty`);

const content = luUtil.updateIntent(file.content, intentName, intent);
const projectId = state.projectId;
return await actions.updateLuFile({ id: file.id, projectId, content });
};

const removeLuIntent = async (id: string, intentName: string) => {
const file = luFileResolver(id);
if (!file) throw new Error(`lu file ${id} not found`);
if (!intentName) throw new Error(`intentName is missing or empty`);

const content = luUtil.removeIntent(file.content, intentName);
const projectId = state.projectId;
return await actions.updateLuFile({ id: file.id, projectId, content });
};

const getLuIntents = (id: string): LuIntentSection[] => {
if (id === undefined) throw new Error('must have a file id');
const focusedDialogId = state.focusPath.split('#').shift() || id;
const file = luFileResolver(focusedDialogId);
if (!file) throw new Error(`lu file ${id} not found`);
return file.intents;
};

return mapValues(api, fn => createThrottledFunc(fn));
const getLuIntent = (id: string, intentName: string): LuIntentSection | undefined => {
const file = luFileResolver(id);
if (!file) throw new Error(`lu file ${id} not found`);
return file.intents.find(({ Name }) => Name === intentName);
};

return {
addLuIntent,
getLuIntents,
getLuIntent,
updateLuIntent: createThrottledFunc(updateLuIntent),
removeLuIntent,
};
}

export function useLuApi() {
Expand All @@ -73,7 +77,9 @@ export function useLuApi() {

return () => {
Object.keys(newApi).forEach(apiName => {
newApi[apiName].flush();
if (typeof newApi[apiName].flush === 'function') {
newApi[apiName].flush();
}
});
};
}, [projectId, focusPath]);
Expand Down
4 changes: 2 additions & 2 deletions Composer/packages/extensions/extension/src/hooks/useLgApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { LgTemplateRef, LgMetaData, BaseSchema, LgType, ShellApi } from '@bfc/sh
* LG CRUD lib
*/
export const useLgApi = (shellApi: ShellApi) => {
const { removeLgTemplates, getLgTemplates, updateLgTemplate } = shellApi;
const { removeLgTemplates, getLgTemplates, addLgTemplate } = shellApi;

const deleteLgTemplates = (lgFileId: string, lgTemplates: string[]) => {
const normalizedLgTemplates = lgTemplates
Expand Down Expand Up @@ -43,7 +43,7 @@ export const useLgApi = (shellApi: ShellApi) => {
const newLgType = new LgType(hostActionData.$kind, hostFieldName).toString();
const newLgTemplateName = new LgMetaData(newLgType, hostActionId).toString();
const newLgTemplateRefStr = new LgTemplateRef(newLgTemplateName).toString();
await updateLgTemplate(lgFileId, newLgTemplateName, lgText);
await addLgTemplate(lgFileId, newLgTemplateName, lgText);
return newLgTemplateRefStr;
};

Expand Down
5 changes: 3 additions & 2 deletions Composer/packages/lib/shared/src/types/shell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,14 @@ export interface ShellApi {
onSelect: (ids: string[]) => void;
getLgTemplates: (id: string) => LgTemplate[];
copyLgTemplate: (id: string, fromTemplateName: string, toTemplateName?: string) => Promise<void>;
addLgTemplate: (id: string, templateName: string, templateStr: string) => Promise<void>;
updateLgTemplate: (id: string, templateName: string, templateStr: string) => Promise<void>;
removeLgTemplate: (id: string, templateName: string) => Promise<void>;
removeLgTemplates: (id: string, templateNames: string[]) => Promise<void>;
getLuIntent: (id: string, intentName: string) => LuIntentSection | undefined;
getLuIntents: (id: string) => LuIntentSection[];
addLuIntent: (id: string, intentName: string, intent: LuIntentSection | undefined) => Promise<void>;
updateLuIntent: (id: string, intentName: string, intent: LuIntentSection | undefined) => Promise<void>;
addLuIntent: (id: string, intentName: string, intent: LuIntentSection) => Promise<void>;
updateLuIntent: (id: string, intentName: string, intent: LuIntentSection) => Promise<void>;
removeLuIntent: (id: string, intentName: string) => void;
updateRegExIntent: (id: string, intentName: string, pattern: string) => void;
createDialog: (actions: any) => Promise<string | null>;
Expand Down

0 comments on commit 4767c24

Please sign in to comment.