Skip to content

Commit

Permalink
feat: added tag management
Browse files Browse the repository at this point in the history
  • Loading branch information
giuliano176 committed Mar 18, 2022
1 parent 173b9ca commit a989935
Show file tree
Hide file tree
Showing 10 changed files with 136 additions and 68 deletions.
6 changes: 6 additions & 0 deletions src/boot/app/app-loader-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import {
import { getSoapFetch, getXmlSoapFetch } from '../../network/fetch';
import { getTag, getTags, useTag, useTags } from '../../store/tags';
import { useNotify, useRefresh } from '../../store/network';
import { changeTagColor, createTag, deleteTag, renameTag } from '../../network/tags';

// eslint-disable-next-line @typescript-eslint/ban-types
export const getAppFunctions = (pkg: CarbonioModule): Record<string, Function> => ({
Expand Down Expand Up @@ -118,6 +119,11 @@ export const getAppFunctions = (pkg: CarbonioModule): Record<string, Function> =
pushHistory,
goBackHistory,
replaceHistory,
// TAGS
createTag,
renameTag,
changeTagColor,
deleteTag,
// STUFF
useIsMobile,
getBridgedFunctions: (): unknown => {
Expand Down
28 changes: 23 additions & 5 deletions src/network/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/

import { find } from 'lodash';
import { find, forEach, map } from 'lodash';
import { goToLogin } from './go-to-login';
import { Account, ErrorSoapResponse, SoapResponse, SuccessSoapResponse } from '../../types';
import {
Account,
ErrorSoapResponse,
SoapContext,
SoapResponse,
SuccessSoapResponse
} from '../../types';
import { userAgent } from './user-agent';
import { report } from '../reporting';
import { useAccountStore } from '../store/account';
Expand Down Expand Up @@ -73,12 +79,23 @@ const getXmlSession = (context?: any): string => {
return '';
};

const normalizeContext = (context: any): SoapContext => {
if (context.notify) {
// eslint-disable-next-line no-param-reassign
context.notify = map(context.notify, (notify) => ({
...notify,
deleted: notify.deleted?.id?.split(',')
}));
}
return context;
};

const handleResponse = <R>(api: string, res: SoapResponse<R>): R => {
const { pollingInterval, context } = useNetworkStore.getState();
const { pollingInterval, context, noOpTimeout } = useNetworkStore.getState();
const { usedQuota } = useAccountStore.getState();
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
clearTimeout(get().noOpTimeout);
clearTimeout(noOpTimeout);
if (res?.Body?.Fault) {
if (
find(
Expand All @@ -97,7 +114,8 @@ const handleResponse = <R>(api: string, res: SoapResponse<R>): R => {
if (res?.Header?.context) {
const responseUsedQuota =
res.Header.context?.refresh?.mbx?.[0]?.s ?? res.Header.context?.notify?.[0]?.mbx?.[0]?.s;
handleTagSync(res.Header.context);
const _context = normalizeContext(res.Header.context);
handleTagSync(_context);
useAccountStore.setState({
usedQuota: responseUsedQuota ?? usedQuota
});
Expand Down
26 changes: 3 additions & 23 deletions src/network/tags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,44 +17,24 @@ import { useTagStore } from '../store/tags';
import { getSoapFetch } from './fetch';

const set = useTagStore.setState;
export const createTag = (tag: Omit<Tag, 'id'>): Promise<string> =>
export const createTag = (tag: Omit<Tag, 'id'>): Promise<CreateTagResponse> =>
getSoapFetch(SHELL_APP_ID)<CreateTagRequest, CreateTagResponse>('CreateTag', {
_jsns: 'urn:zimbraMail',
tag
}).then((r: CreateTagResponse) => {
set((state) => ({ tags: { ...state.tags, [r.tag[0].id]: r.tag[0] } }));
return r.tag[0].id;
});

export const deleteTag = (id: string): Promise<TagActionResponse> =>
getSoapFetch(SHELL_APP_ID)<TagActionRequest, TagActionResponse>('TagAction', {
_jsns: 'urn:zimbraMail',
action: { op: 'delete', id }
});

export const renameTag = (id: string, name: string): Promise<void> =>
export const renameTag = (id: string, name: string): Promise<TagActionResponse> =>
getSoapFetch(SHELL_APP_ID)<TagActionRequest, TagActionResponse>('TagAction', {
_jsns: 'urn:zimbraMail',
action: { op: 'rename', id, name }
}).then((r: TagActionResponse) => {
set(
produce((state) => {
state.tags[id].name = name;
})
);
});
export const changeTagColor = (id: string, color: string | number): Promise<void> =>
export const changeTagColor = (id: string, color: string | number): Promise<TagActionResponse> =>
getSoapFetch(SHELL_APP_ID)<TagActionRequest, TagActionResponse>('TagAction', {
_jsns: 'urn:zimbraMail',
action: typeof color === 'number' ? { op: 'color', color, id } : { op: 'color', rgb: color, id }
}).then((r: TagActionResponse) => {
set(
produce((state) => {
if (color === 'number') {
state.tags[id].color = color;
} else {
state.tags[id].rgb = color;
}
})
);
});
4 changes: 1 addition & 3 deletions src/shell/shell-view.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { useUserSettings } from '../store/account';
import { ShellUtilityBar, ShellUtilityPanel } from '../utility-bar';
import { useCurrentRoute } from '../history/hooks';
import { useTagStore } from '../store/tags/store';
import { createTag } from '../network/tags';

const Background = styled.div`
background: ${({ theme }) => theme.palette.gray6.regular};
Expand Down Expand Up @@ -45,9 +46,6 @@ function DarkReaderListener() {
export function Shell() {
const [mobileNavOpen, setMobileNavOpen] = useState(false);
const activeRoute = useCurrentRoute();
const tagStore = useTagStore();
console.log('@@ tagStore', tagStore);

return (
<Background>
<DarkReaderListener />
Expand Down
2 changes: 0 additions & 2 deletions src/store/account/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ export const useUserRight = (right: AccountRightName): Array<AccountRightTarget>
export const useUserSettings = (): AccountSettings => useAccountStore((s) => s.settings);
export const useUserSetting = <T = void>(...path: Array<string>): string | T =>
useAccountStore((s) => get(s.settings, join(path, '.')));
// @@ export const useTags = (): Array<Tag> => useAccountStore((s) => s.tags);

export const getUserAccount = (): Account => useAccountStore.getState().account as Account;
export const getUserAccounts = (): Array<Account> => [
Expand All @@ -43,7 +42,6 @@ export const getUserAccounts = (): Array<Account> => [
export const getUserSettings = (): AccountSettings => useAccountStore.getState().settings;
export const getUserSetting = <T = void>(...path: Array<string>): string | T =>
get(useAccountStore.getState().settings, join(path, '.'));
// @@ export const getTags = (): Array<Tag> => useAccountStore.getState().tags;

export const getUserRights = (): AccountRights =>
useAccountStore.getState().account?.rights ?? { targets: [] };
Expand Down
6 changes: 3 additions & 3 deletions src/store/network/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { NotifyObject } from '../../../types';
import { SoapNotify, SoapRefresh } from '../../../types';
import { useNetworkStore } from './store';

export const useNotify = (): NotifyObject[] => {
export const useNotify = (): SoapNotify[] => {
const notify = useNetworkStore((s) => s.context.notify ?? []);
return notify;
};
export const useRefresh = (): NotifyObject => useNetworkStore((s) => s.context.refresh ?? {});
export const useRefresh = (): SoapRefresh => useNetworkStore((s) => s.context.refresh ?? {});
73 changes: 62 additions & 11 deletions src/store/tags/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,76 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/

import { reduce } from 'lodash';
import { forEach, reduce } from 'lodash';
import { SoapContext, Tag, Tags } from '../../../types';
import { useTagStore } from './store';

export const handleTagRefresh = (tags: Array<Tag>): Tags =>
reduce(
tags,
(acc: Tags, val: Tag): Tags => {
// eslint-disable-next-line no-param-reassign
acc[val.id] = val;
return acc;
},
{}
);

export const handleTagCreated = (tags: Tags, created: Array<Tag>): Tags =>
reduce(
created,
(acc: Tags, val: Tag): Tags => {
// eslint-disable-next-line no-param-reassign
acc[val.id] = val;
return acc;
},
tags
);
export const handleTagModified = (tags: Tags, modified: Array<Partial<Tag>>): Tags =>
reduce(
modified,
(acc: Tags, val: Partial<Tag>): Tags => {
if (val.id) {
// eslint-disable-next-line no-param-reassign
acc[val.id] = { ...tags[val.id], ...val };
}
return acc;
},
tags
);
export const handleTagDeleted = (tags: Tags, deleted: string[]): Tags =>
reduce(
deleted,
(acc, val) => {
// eslint-disable-next-line no-param-reassign
delete acc[val];
return acc;
},
tags
);
export const handleTagSync = (context: SoapContext): void => {
if (context.refresh?.tags?.tag) {
useTagStore.setState({
tags: reduce(
context.refresh.tags?.tag,
(acc: Tags, val: Tag): Tags => {
// eslint-disable-next-line no-param-reassign
acc[val.id] = val;
return acc;
},
{}
)
tags: handleTagRefresh(context.refresh.tags.tag)
});
}
if (context.notify) {
console.log(context.notify);
forEach(context.notify, (notify) => {
if (notify.created?.tag) {
useTagStore.setState({
tags: handleTagCreated(useTagStore.getState().tags, notify.created?.tag)
});
}
if (notify.modified?.tag) {
useTagStore.setState({
tags: handleTagModified(useTagStore.getState().tags, notify.modified?.tag)
});
}
if (notify.deleted) {
useTagStore.setState({
tags: handleTagDeleted(useTagStore.getState().tags, notify.deleted)
});
}
});
}
};
17 changes: 6 additions & 11 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
{
"extends": "@zextras/carbonio-ui-configs/rules/typescript.json",
"compilerOptions": {
"skipLibCheck": true
},
"include": [
"types/**/*.d.ts",
"src/**/*.ts",
"src/**/*.tsx"],
"exclude": [
"node_modules"
]
"extends": "@zextras/carbonio-ui-configs/rules/typescript.json",
"compilerOptions": {
"skipLibCheck": true
},
"include": ["types/**/*.d.ts", "src/**/*.ts", "src/**/*.tsx"],
"exclude": ["node_modules"]
}
19 changes: 12 additions & 7 deletions types/exports/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,15 @@ import {
import { ActionFactory, AnyFunction, CombinedActionFactory, Action } from '../integrations';
import {
AccountSettings,
// @@ Tag,
Account,
NotifyObject,
AccountRights,
AccountRightName,
AccountRightTarget,
SoapFetch
} from '../account';
import { Mods } from '../network';
import { Mods, TagActionResponse, CreateTagResponse, SoapNotify, SoapRefresh } from '../network';
import { HistoryParams, ShellModes } from '../misc';
import { Tag, Tags } from '../tags';

export const getBridgedFunctions: () => {
addBoard: (path: string, context?: unknown | { app: string }) => void;
Expand Down Expand Up @@ -93,8 +92,14 @@ export const getUserAccount: () => Account;
export const getUserAccounts: () => Array<Account>;
export const getUserRights: () => AccountRights;
export const getUserRight: (right: AccountRightName) => Array<AccountRightTarget>;
// @@ export const useTags: () => Array<Tag>;
// @@ export const getTags: () => Array<Tag>;
export const useTags: () => Tags;
export const getTags: () => Tags;
export const useTag: (id: string) => Tag;
export const getTag: (id: string) => Tag;
export const createTag: (tag: Omit<Tag, 'id'>) => Promise<CreateTagResponse>;
export const renameTag: (id: string, name: string) => Promise<TagActionResponse>;
export const deleteTag: (id: string) => Promise<TagActionResponse>;
export const changeTagColor: (id: string, color: number | string) => Promise<TagActionResponse>;
export const useUserSettings: () => AccountSettings;
export const useUserSetting: <T = void>(...path: Array<string>) => string | T;
export const getUserSettings: () => AccountSettings;
Expand All @@ -103,8 +108,8 @@ export const store: {
store: Store<any>;
setReducer(nextReducer: Reducer): void;
};
export const useNotify: () => Array<NotifyObject>;
export const useRefresh: () => NotifyObject;
export const useNotify: () => Array<SoapNotify>;
export const useRefresh: () => SoapRefresh;
export const Applink: FC<LinkProps>;
export const Spinner: FC;
export const useAddBoardCallback: () => (
Expand Down
23 changes: 20 additions & 3 deletions types/network/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,20 +126,37 @@ export type AvailableLocalesResponse = {
locale: Array<Locale>;
};
export type SoapContext = {
refresh?: NotifyObject;
notify?: [NotifyObject];
refresh?: SoapRefresh;
notify?: Array<SoapNotify>;
change?: { token: number };
session?: { id: number; _content: number };
};

export type NotifyObject = {
export type SoapRefresh = {
seq?: number;
version?: string;
mbx?: [{ s: number }];
folder?: Array<unknown>;
tags?: { tag: Array<Tag> };
};

export type SoapNotify = {
seq?: number;
created?: {
m?: Array<unknown>;
c?: Array<unknown>;
folder?: Array<unknown>;
tag?: Array<Tag>;
};
modified?: {
m?: Array<unknown>;
c?: Array<unknown>;
folder?: Array<unknown>;
tag?: Array<Partial<Tag>>;
};
deleted: string[];
};

export type NetworkState = {
noOpTimeout: unknown;
context: SoapContext;
Expand Down

0 comments on commit a989935

Please sign in to comment.