Skip to content

Commit

Permalink
Merge pull request #1018 from gettakaro/add-import-export-to-frontend
Browse files Browse the repository at this point in the history
  • Loading branch information
niekcandaele authored May 29, 2024
2 parents 3a7006f + 3315c94 commit 7685ccc
Show file tree
Hide file tree
Showing 12 changed files with 302 additions and 10 deletions.
2 changes: 1 addition & 1 deletion packages/app-api/src/controllers/ModuleController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export class ModuleController {
}

@UseBefore(AuthService.getAuthMiddleware([PERMISSIONS.READ_MODULES]))
@Post('/module/export/:id')
@Get('/module/:id/export')
@ResponseSchema(ModuleExportDTOAPI)
async export(@Req() req: AuthenticatedRequest, @Params() params: ParamId) {
const service = new ModuleService(req.domainId);
Expand Down
6 changes: 3 additions & 3 deletions packages/app-api/src/service/ModuleService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,15 +245,15 @@ export class ModuleService extends TakaroService<ModuleModel, ModuleOutputDTO, M
mod.name = `${mod.name}-imported`;
}

return this.seedModule(mod);
return this.seedModule(mod, true);
}

async seedBuiltinModules() {
const modules = getModules();
await Promise.all(modules.map((m) => this.seedModule(m)));
}

async seedModule(builtin: BuiltinModule<unknown>) {
async seedModule(builtin: BuiltinModule<unknown>, isImport = false) {
const commandService = new CommandService(this.domainId);
const hookService = new HookService(this.domainId);
const cronjobService = new CronJobService(this.domainId);
Expand All @@ -268,7 +268,7 @@ export class ModuleService extends TakaroService<ModuleModel, ModuleOutputDTO, M
mod = await this.create(
new ModuleCreateInternalDTO({
...builtin,
builtin: builtin.name,
builtin: isImport ? null : builtin.name,
permissions: await Promise.all(builtin.permissions.map((p) => new PermissionOutputDTO(p))),
})
);
Expand Down
63 changes: 59 additions & 4 deletions packages/lib-apiclient/src/generated/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,30 @@ export interface BaseTakaroEvent {
* @interface BuiltinModule
*/
export interface BuiltinModule {
/**
*
* @type {string}
* @memberof BuiltinModule
*/
name: string;
/**
*
* @type {string}
* @memberof BuiltinModule
*/
description: string;
/**
*
* @type {string}
* @memberof BuiltinModule
*/
configSchema: string;
/**
*
* @type {string}
* @memberof BuiltinModule
*/
uiSchema: string;
/**
*
* @type {Array<ICommand>}
Expand All @@ -211,10 +235,10 @@ export interface BuiltinModule {
functions: Array<IFunction>;
/**
*
* @type {Array<any>}
* @type {Array<IPermission>}
* @memberof BuiltinModule
*/
permissions: Array<any>;
permissions: Array<IPermission>;
}
/**
*
Expand Down Expand Up @@ -3642,6 +3666,37 @@ export interface IMessageOptsDTO {
*/
recipient: IPlayerReferenceDTO;
}
/**
*
* @export
* @interface IPermission
*/
export interface IPermission {
/**
*
* @type {string}
* @memberof IPermission
*/
permission: string;
/**
*
* @type {string}
* @memberof IPermission
*/
description: string;
/**
*
* @type {string}
* @memberof IPermission
*/
friendlyName: string;
/**
*
* @type {boolean}
* @memberof IPermission
*/
canHaveCount?: boolean;
}
/**
*
* @export
Expand Down Expand Up @@ -14872,15 +14927,15 @@ export const ModuleApiAxiosParamCreator = function (configuration?: Configuratio
moduleControllerExport: async (id: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'id' is not null or undefined
assertParamExists('moduleControllerExport', 'id', id);
const localVarPath = `/module/export/{id}`.replace(`{${'id'}}`, encodeURIComponent(String(id)));
const localVarPath = `/module/{id}/export`.replace(`{${'id'}}`, encodeURIComponent(String(id)));
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}

const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options };
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options };
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
AiOutlineLink as LinkIcon,
AiOutlineEye as ViewIcon,
AiOutlineCopy as CopyIcon,
AiOutlineExport as ExportIcon,
} from 'react-icons/ai';

interface IModuleCardProps {
Expand Down Expand Up @@ -70,6 +71,11 @@ export const ModuleDefinitionCard: FC<IModuleCardProps> = ({ mod }) => {
window.open(`/studio/${mod.id}`, '_blank');
};

const handleOnExportClick = async (e: MouseEvent) => {
e.stopPropagation();
navigate({ to: '/modules/$moduleId/export', params: { moduleId: mod.id } });
};

return (
<>
<Card data-testid={`${mod.name}`}>
Expand Down Expand Up @@ -117,6 +123,7 @@ export const ModuleDefinitionCard: FC<IModuleCardProps> = ({ mod }) => {
<Dropdown.Menu.Group>
<Dropdown.Menu.Item icon={<CopyIcon />} onClick={handleOnCopyClick} label="Copy module" />
<Dropdown.Menu.Item icon={<LinkIcon />} onClick={handleOnOpenClick} label="Open in Studio" />
<Dropdown.Menu.Item icon={<ExportIcon />} onClick={handleOnExportClick} label="Export (JSON)" />
</Dropdown.Menu.Group>
</Dropdown.Menu>
</Dropdown>
Expand Down
4 changes: 4 additions & 0 deletions packages/web-main/src/queries/modules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,8 @@ export {
useCommandCreate,
useCommandRemove,
useCommandUpdate,

// import/export
moduleExportOptions,
useModuleImport,
} from './queries';
33 changes: 32 additions & 1 deletion packages/web-main/src/queries/modules/queries.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useMutation, useQueryClient, queryOptions, infiniteQueryOptions } from '@tanstack/react-query';
import { getApiClient } from 'util/getApiClient';
import {
BuiltinModule,
CommandCreateDTO,
CommandOutputDTO,
CommandOutputDTOAPI,
Expand All @@ -20,6 +21,7 @@ import {
IdUuidDTO,
IdUuidDTOAPI,
ModuleCreateDTO,
ModuleExportDTOAPI,
ModuleOutputArrayDTOAPI,
ModuleOutputDTO,
ModuleOutputDTOAPI,
Expand All @@ -28,12 +30,13 @@ import {
} from '@takaro/apiclient';

import { queryParamsToArray, hasNextPage, mutationWrapper } from '../util';
import { AxiosError } from 'axios';
import { AxiosError, AxiosResponse } from 'axios';
import { ErrorMessageMapping } from '@takaro/lib-components/src/errors';

export const moduleKeys = {
all: ['modules'] as const,
detail: (id: string) => [...moduleKeys.all, 'detail', id] as const,
export: (id: string) => [...moduleKeys.all, 'export', id] as const,
list: () => [...moduleKeys.all, 'list'] as const,

hooks: {
Expand Down Expand Up @@ -126,12 +129,30 @@ export const useModuleRemove = () => {
onSuccess: async (removedModule: IdUuidDTO) => {
await queryClient.invalidateQueries({ queryKey: moduleKeys.list() });
await queryClient.invalidateQueries({ queryKey: moduleKeys.detail(removedModule.id) });
await queryClient.invalidateQueries({ queryKey: moduleKeys.export(removedModule.id) });
},
}),
{}
);
};

export const moduleExportOptions = (moduleId: string) =>
queryOptions<ModuleExportDTOAPI['data'], AxiosError<ModuleExportDTOAPI>>({
queryKey: moduleKeys.export(moduleId),
queryFn: async () => (await getApiClient().module.moduleControllerExport(moduleId)).data.data,
});

export const useModuleImport = () => {
const apiClient = getApiClient();

return mutationWrapper<void, BuiltinModule>(
useMutation<AxiosResponse<void>, AxiosError<ModuleExportDTOAPI>, BuiltinModule>({
mutationFn: async (mod) => await apiClient.module.moduleControllerImport(mod),
}),
{}
);
};

interface ModuleUpdate {
moduleUpdate: ModuleUpdateDTO;
id: string;
Expand All @@ -146,6 +167,7 @@ export const useModuleUpdate = () => {
(await apiClient.module.moduleControllerUpdate(id, moduleUpdate)).data.data,
onSuccess: async (updatedModule: ModuleOutputDTO) => {
await queryClient.invalidateQueries({ queryKey: moduleKeys.list() });
await queryClient.invalidateQueries({ queryKey: moduleKeys.export(updatedModule.id) });
return queryClient.setQueryData(moduleKeys.detail(updatedModule.id), updatedModule);
},
}),
Expand All @@ -171,6 +193,7 @@ export const useHookCreate = () => {
mutationFn: async (hook) => (await apiClient.hook.hookControllerCreate(hook)).data.data,
onSuccess: async (newHook: HookOutputDTO) => {
await queryClient.invalidateQueries({ queryKey: moduleKeys.hooks.list() });
await queryClient.invalidateQueries({ queryKey: moduleKeys.export(newHook.moduleId) });
queryClient.setQueryData<ModuleOutputDTO>(moduleKeys.detail(newHook.moduleId), (prev) => {
if (!prev) {
// we are updating a module that does not have a cache entry
Expand Down Expand Up @@ -201,6 +224,7 @@ export const useHookRemove = ({ moduleId }) => {
mutationFn: async ({ hookId }) => (await apiClient.hook.hookControllerRemove(hookId)).data.data,
onSuccess: async (removedHook: IdUuidDTO) => {
await queryClient.invalidateQueries({ queryKey: moduleKeys.hooks.list() });
await queryClient.invalidateQueries({ queryKey: moduleKeys.export(moduleId) });
queryClient.setQueryData<ModuleOutputDTO>(moduleKeys.detail(moduleId), (prev) => {
if (!prev) {
return prev;
Expand Down Expand Up @@ -230,6 +254,7 @@ export const useHookUpdate = () => {
mutationFn: async ({ hookId, hook }) => (await apiClient.hook.hookControllerUpdate(hookId, hook)).data.data,
onSuccess: async (updatedHook: HookOutputDTO) => {
await queryClient.invalidateQueries({ queryKey: moduleKeys.hooks.list() });
await queryClient.invalidateQueries({ queryKey: moduleKeys.export(updatedHook.moduleId) });
queryClient.setQueryData<ModuleOutputDTO>(moduleKeys.detail(updatedHook.moduleId), (prev) => {
if (!prev) {
return prev;
Expand Down Expand Up @@ -265,6 +290,7 @@ export const useCommandCreate = () => {
mutationFn: async (command) => (await apiClient.command.commandControllerCreate(command)).data.data,
onSuccess: async (newCommand: CommandOutputDTO) => {
await queryClient.invalidateQueries({ queryKey: moduleKeys.commands.list() });
await queryClient.invalidateQueries({ queryKey: moduleKeys.export(newCommand.moduleId) });
queryClient.setQueryData<ModuleOutputDTO>(moduleKeys.detail(newCommand.moduleId), (prev) => {
if (!prev) {
return prev;
Expand Down Expand Up @@ -295,6 +321,7 @@ export const useCommandUpdate = () => {
(await apiClient.command.commandControllerUpdate(commandId, command)).data.data,
onSuccess: async (updatedCommand: CommandOutputDTO) => {
await queryClient.invalidateQueries({ queryKey: moduleKeys.commands.list() });
await queryClient.invalidateQueries({ queryKey: moduleKeys.export(updatedCommand.moduleId) });
queryClient.setQueryData<ModuleOutputDTO>(moduleKeys.detail(updatedCommand.id), (prev) => {
if (!prev) {
return prev;
Expand Down Expand Up @@ -328,6 +355,7 @@ export const useCommandRemove = ({ moduleId }) => {
onSuccess: async (removedCommand: IdUuidDTO) => {
// invalidate list of commands
await queryClient.invalidateQueries({ queryKey: moduleKeys.commands.list() });
await queryClient.invalidateQueries({ queryKey: moduleKeys.export(moduleId) });
queryClient.setQueryData<ModuleOutputDTO>(moduleKeys.detail(moduleId), (prev) => {
if (!prev) {
return prev;
Expand Down Expand Up @@ -364,6 +392,7 @@ export const useCronJobCreate = () => {
onSuccess: async (newCronJob: CronJobOutputDTO) => {
// invalidate list of cronjobs
await queryClient.invalidateQueries({ queryKey: moduleKeys.cronJobs.list() });
await queryClient.invalidateQueries({ queryKey: moduleKeys.export(newCronJob.moduleId) });
queryClient.setQueryData<ModuleOutputDTO>(moduleKeys.detail(newCronJob.moduleId), (prev) => {
if (!prev) {
return prev;
Expand Down Expand Up @@ -396,6 +425,7 @@ export const useCronJobUpdate = () => {
onSuccess: async (updatedCronJob: CronJobOutputDTO) => {
// invalidate list of cronjob
await queryClient.invalidateQueries({ queryKey: moduleKeys.cronJobs.list() });
await queryClient.invalidateQueries({ queryKey: moduleKeys.export(updatedCronJob.moduleId) });
queryClient.setQueryData<ModuleOutputDTO>(moduleKeys.detail(updatedCronJob.moduleId), (prev) => {
if (!prev) {
return prev;
Expand Down Expand Up @@ -429,6 +459,7 @@ export const useCronJobRemove = ({ moduleId }: { moduleId: string }) => {
(await apiClient.cronjob.cronJobControllerRemove(cronJobId)).data.data,
onSuccess: async (removedCronJob: IdUuidDTO) => {
await queryClient.invalidateQueries({ queryKey: moduleKeys.cronJobs.list() });
await queryClient.invalidateQueries({ queryKey: moduleKeys.export(moduleId) });

queryClient.setQueryData<ModuleOutputDTO>(moduleKeys.detail(moduleId), (prev) => {
if (!prev) {
Expand Down
22 changes: 22 additions & 0 deletions packages/web-main/src/routeTree.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { Route as AuthGlobalSettingsGameserversImport } from './routes/_auth/_gl
import { Route as AuthGlobalSettingsDiscordImport } from './routes/_auth/_global/settings/discord';
import { Route as AuthGlobalRolesCreateImport } from './routes/_auth/_global/roles.create';
import { Route as AuthGlobalPlayerPlayerIdImport } from './routes/_auth/_global/player.$playerId';
import { Route as AuthGlobalModulesImportImport } from './routes/_auth/_global/modules.import';
import { Route as AuthGlobalModulesCreateImport } from './routes/_auth/_global/modules.create';
import { Route as AuthGlobalPlayerPlayerIdIndexImport } from './routes/_auth/_global/player.$playerId/index';
import { Route as AuthGlobalGameserversCreateIndexImport } from './routes/_auth/_global/gameservers.create.index';
Expand All @@ -57,6 +58,7 @@ import { Route as AuthGlobalPlayerPlayerIdEventsImport } from './routes/_auth/_g
import { Route as AuthGlobalPlayerPlayerIdEconomyImport } from './routes/_auth/_global/player.$playerId/economy';
import { Route as AuthGlobalModulesModuleIdViewImport } from './routes/_auth/_global/modules.$moduleId.view';
import { Route as AuthGlobalModulesModuleIdUpdateImport } from './routes/_auth/_global/modules.$moduleId.update';
import { Route as AuthGlobalModulesModuleIdExportImport } from './routes/_auth/_global/modules.$moduleId.export';
import { Route as AuthGlobalModulesModuleIdCopyImport } from './routes/_auth/_global/modules.$moduleId.copy';
import { Route as AuthGlobalGameserversUpdateGameServerIdImport } from './routes/_auth/_global/gameservers.update.$gameServerId';
import { Route as AuthGlobalGameserversCreateImportImport } from './routes/_auth/_global/gameservers.create.import';
Expand Down Expand Up @@ -222,6 +224,11 @@ const AuthGlobalPlayerPlayerIdRoute = AuthGlobalPlayerPlayerIdImport.update({
getParentRoute: () => AuthGlobalRoute,
} as any);

const AuthGlobalModulesImportRoute = AuthGlobalModulesImportImport.update({
path: '/import',
getParentRoute: () => AuthGlobalModulesRoute,
} as any);

const AuthGlobalModulesCreateRoute = AuthGlobalModulesCreateImport.update({
path: '/create',
getParentRoute: () => AuthGlobalModulesRoute,
Expand Down Expand Up @@ -297,6 +304,11 @@ const AuthGlobalModulesModuleIdUpdateRoute = AuthGlobalModulesModuleIdUpdateImpo
getParentRoute: () => AuthGlobalModulesRoute,
} as any);

const AuthGlobalModulesModuleIdExportRoute = AuthGlobalModulesModuleIdExportImport.update({
path: '/$moduleId/export',
getParentRoute: () => AuthGlobalModulesRoute,
} as any);

const AuthGlobalModulesModuleIdCopyRoute = AuthGlobalModulesModuleIdCopyImport.update({
path: '/$moduleId/copy',
getParentRoute: () => AuthGlobalModulesRoute,
Expand Down Expand Up @@ -426,6 +438,10 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof AuthGlobalModulesCreateImport;
parentRoute: typeof AuthGlobalModulesImport;
};
'/_auth/_global/modules/import': {
preLoaderRoute: typeof AuthGlobalModulesImportImport;
parentRoute: typeof AuthGlobalModulesImport;
};
'/_auth/_global/player/$playerId': {
preLoaderRoute: typeof AuthGlobalPlayerPlayerIdImport;
parentRoute: typeof AuthGlobalImport;
Expand Down Expand Up @@ -478,6 +494,10 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof AuthGlobalModulesModuleIdCopyImport;
parentRoute: typeof AuthGlobalModulesImport;
};
'/_auth/_global/modules/$moduleId/export': {
preLoaderRoute: typeof AuthGlobalModulesModuleIdExportImport;
parentRoute: typeof AuthGlobalModulesImport;
};
'/_auth/_global/modules/$moduleId/update': {
preLoaderRoute: typeof AuthGlobalModulesModuleIdUpdateImport;
parentRoute: typeof AuthGlobalModulesImport;
Expand Down Expand Up @@ -567,7 +587,9 @@ export const routeTree = rootRoute.addChildren([
]),
AuthGlobalModulesRoute.addChildren([
AuthGlobalModulesCreateRoute,
AuthGlobalModulesImportRoute,
AuthGlobalModulesModuleIdCopyRoute,
AuthGlobalModulesModuleIdExportRoute,
AuthGlobalModulesModuleIdUpdateRoute,
AuthGlobalModulesModuleIdViewRoute,
]),
Expand Down

Large diffs are not rendered by default.

Loading

0 comments on commit 7685ccc

Please sign in to comment.