feat(config): add reusable security profiles and network targets with route reference resolution
This commit is contained in:
@@ -110,7 +110,7 @@ export const configStatePart = await appState.getStatePart<IConfigState>(
|
||||
// Determine initial view from URL path
|
||||
const getInitialView = (): string => {
|
||||
const path = typeof window !== 'undefined' ? window.location.pathname : '/';
|
||||
const validViews = ['overview', 'network', 'emails', 'logs', 'routes', 'apitokens', 'configuration', 'security', 'certificates', 'remoteingress'];
|
||||
const validViews = ['overview', 'network', 'emails', 'logs', 'routes', 'apitokens', 'configuration', 'security', 'certificates', 'remoteingress', 'securityprofiles', 'networktargets'];
|
||||
const segments = path.split('/').filter(Boolean);
|
||||
const view = segments[0];
|
||||
return validViews.includes(view) ? view : 'overview';
|
||||
@@ -444,6 +444,13 @@ export const setActiveViewAction = uiStatePart.createAction<string>(async (state
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// If switching to security profiles or network targets views, fetch profiles/targets data
|
||||
if ((viewName === 'securityprofiles' || viewName === 'networktargets') && currentState.activeView !== viewName) {
|
||||
setTimeout(() => {
|
||||
profilesTargetsStatePart.dispatchAction(fetchProfilesAndTargetsAction, null);
|
||||
}, 100);
|
||||
}
|
||||
|
||||
return {
|
||||
...currentState,
|
||||
activeView: viewName,
|
||||
@@ -1133,6 +1140,241 @@ export const clearNewClientConfigAction = vpnStatePart.createAction(
|
||||
},
|
||||
);
|
||||
|
||||
// ============================================================================
|
||||
// Security Profiles & Network Targets State
|
||||
// ============================================================================
|
||||
|
||||
export interface IProfilesTargetsState {
|
||||
profiles: interfaces.data.ISecurityProfile[];
|
||||
targets: interfaces.data.INetworkTarget[];
|
||||
isLoading: boolean;
|
||||
error: string | null;
|
||||
lastUpdated: number;
|
||||
}
|
||||
|
||||
export const profilesTargetsStatePart = await appState.getStatePart<IProfilesTargetsState>(
|
||||
'profilesTargets',
|
||||
{
|
||||
profiles: [],
|
||||
targets: [],
|
||||
isLoading: false,
|
||||
error: null,
|
||||
lastUpdated: 0,
|
||||
},
|
||||
'soft'
|
||||
);
|
||||
|
||||
// ============================================================================
|
||||
// Security Profiles & Network Targets Actions
|
||||
// ============================================================================
|
||||
|
||||
export const fetchProfilesAndTargetsAction = profilesTargetsStatePart.createAction(
|
||||
async (statePartArg): Promise<IProfilesTargetsState> => {
|
||||
const context = getActionContext();
|
||||
const currentState = statePartArg.getState()!;
|
||||
if (!context.identity) return currentState;
|
||||
|
||||
try {
|
||||
const profilesRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
|
||||
interfaces.requests.IReq_GetSecurityProfiles
|
||||
>('/typedrequest', 'getSecurityProfiles');
|
||||
|
||||
const targetsRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
|
||||
interfaces.requests.IReq_GetNetworkTargets
|
||||
>('/typedrequest', 'getNetworkTargets');
|
||||
|
||||
const [profilesResponse, targetsResponse] = await Promise.all([
|
||||
profilesRequest.fire({ identity: context.identity }),
|
||||
targetsRequest.fire({ identity: context.identity }),
|
||||
]);
|
||||
|
||||
return {
|
||||
profiles: profilesResponse.profiles,
|
||||
targets: targetsResponse.targets,
|
||||
isLoading: false,
|
||||
error: null,
|
||||
lastUpdated: Date.now(),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
...currentState,
|
||||
isLoading: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to fetch profiles/targets',
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const createProfileAction = profilesTargetsStatePart.createAction<{
|
||||
name: string;
|
||||
description?: string;
|
||||
security: any;
|
||||
extendsProfiles?: string[];
|
||||
}>(async (statePartArg, dataArg, actionContext): Promise<IProfilesTargetsState> => {
|
||||
const context = getActionContext();
|
||||
try {
|
||||
const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
|
||||
interfaces.requests.IReq_CreateSecurityProfile
|
||||
>('/typedrequest', 'createSecurityProfile');
|
||||
await request.fire({
|
||||
identity: context.identity!,
|
||||
name: dataArg.name,
|
||||
description: dataArg.description,
|
||||
security: dataArg.security,
|
||||
extendsProfiles: dataArg.extendsProfiles,
|
||||
});
|
||||
return await actionContext!.dispatch(fetchProfilesAndTargetsAction, null);
|
||||
} catch (error: unknown) {
|
||||
return {
|
||||
...statePartArg.getState()!,
|
||||
error: error instanceof Error ? error.message : 'Failed to create profile',
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
export const updateProfileAction = profilesTargetsStatePart.createAction<{
|
||||
id: string;
|
||||
name?: string;
|
||||
description?: string;
|
||||
security?: any;
|
||||
extendsProfiles?: string[];
|
||||
}>(async (statePartArg, dataArg, actionContext): Promise<IProfilesTargetsState> => {
|
||||
const context = getActionContext();
|
||||
try {
|
||||
const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
|
||||
interfaces.requests.IReq_UpdateSecurityProfile
|
||||
>('/typedrequest', 'updateSecurityProfile');
|
||||
await request.fire({
|
||||
identity: context.identity!,
|
||||
id: dataArg.id,
|
||||
name: dataArg.name,
|
||||
description: dataArg.description,
|
||||
security: dataArg.security,
|
||||
extendsProfiles: dataArg.extendsProfiles,
|
||||
});
|
||||
return await actionContext!.dispatch(fetchProfilesAndTargetsAction, null);
|
||||
} catch (error: unknown) {
|
||||
return {
|
||||
...statePartArg.getState()!,
|
||||
error: error instanceof Error ? error.message : 'Failed to update profile',
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
export const deleteProfileAction = profilesTargetsStatePart.createAction<{
|
||||
id: string;
|
||||
force?: boolean;
|
||||
}>(async (statePartArg, dataArg, actionContext): Promise<IProfilesTargetsState> => {
|
||||
const context = getActionContext();
|
||||
try {
|
||||
const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
|
||||
interfaces.requests.IReq_DeleteSecurityProfile
|
||||
>('/typedrequest', 'deleteSecurityProfile');
|
||||
const response = await request.fire({
|
||||
identity: context.identity!,
|
||||
id: dataArg.id,
|
||||
force: dataArg.force,
|
||||
});
|
||||
if (!response.success) {
|
||||
return {
|
||||
...statePartArg.getState()!,
|
||||
error: response.message || 'Failed to delete profile',
|
||||
};
|
||||
}
|
||||
return await actionContext!.dispatch(fetchProfilesAndTargetsAction, null);
|
||||
} catch (error: unknown) {
|
||||
return {
|
||||
...statePartArg.getState()!,
|
||||
error: error instanceof Error ? error.message : 'Failed to delete profile',
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
export const createTargetAction = profilesTargetsStatePart.createAction<{
|
||||
name: string;
|
||||
description?: string;
|
||||
host: string | string[];
|
||||
port: number;
|
||||
}>(async (statePartArg, dataArg, actionContext): Promise<IProfilesTargetsState> => {
|
||||
const context = getActionContext();
|
||||
try {
|
||||
const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
|
||||
interfaces.requests.IReq_CreateNetworkTarget
|
||||
>('/typedrequest', 'createNetworkTarget');
|
||||
await request.fire({
|
||||
identity: context.identity!,
|
||||
name: dataArg.name,
|
||||
description: dataArg.description,
|
||||
host: dataArg.host,
|
||||
port: dataArg.port,
|
||||
});
|
||||
return await actionContext!.dispatch(fetchProfilesAndTargetsAction, null);
|
||||
} catch (error: unknown) {
|
||||
return {
|
||||
...statePartArg.getState()!,
|
||||
error: error instanceof Error ? error.message : 'Failed to create target',
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
export const updateTargetAction = profilesTargetsStatePart.createAction<{
|
||||
id: string;
|
||||
name?: string;
|
||||
description?: string;
|
||||
host?: string | string[];
|
||||
port?: number;
|
||||
}>(async (statePartArg, dataArg, actionContext): Promise<IProfilesTargetsState> => {
|
||||
const context = getActionContext();
|
||||
try {
|
||||
const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
|
||||
interfaces.requests.IReq_UpdateNetworkTarget
|
||||
>('/typedrequest', 'updateNetworkTarget');
|
||||
await request.fire({
|
||||
identity: context.identity!,
|
||||
id: dataArg.id,
|
||||
name: dataArg.name,
|
||||
description: dataArg.description,
|
||||
host: dataArg.host,
|
||||
port: dataArg.port,
|
||||
});
|
||||
return await actionContext!.dispatch(fetchProfilesAndTargetsAction, null);
|
||||
} catch (error: unknown) {
|
||||
return {
|
||||
...statePartArg.getState()!,
|
||||
error: error instanceof Error ? error.message : 'Failed to update target',
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
export const deleteTargetAction = profilesTargetsStatePart.createAction<{
|
||||
id: string;
|
||||
force?: boolean;
|
||||
}>(async (statePartArg, dataArg, actionContext): Promise<IProfilesTargetsState> => {
|
||||
const context = getActionContext();
|
||||
try {
|
||||
const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
|
||||
interfaces.requests.IReq_DeleteNetworkTarget
|
||||
>('/typedrequest', 'deleteNetworkTarget');
|
||||
const response = await request.fire({
|
||||
identity: context.identity!,
|
||||
id: dataArg.id,
|
||||
force: dataArg.force,
|
||||
});
|
||||
if (!response.success) {
|
||||
return {
|
||||
...statePartArg.getState()!,
|
||||
error: response.message || 'Failed to delete target',
|
||||
};
|
||||
}
|
||||
return await actionContext!.dispatch(fetchProfilesAndTargetsAction, null);
|
||||
} catch (error: unknown) {
|
||||
return {
|
||||
...statePartArg.getState()!,
|
||||
error: error instanceof Error ? error.message : 'Failed to delete target',
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Route Management Actions
|
||||
// ============================================================================
|
||||
|
||||
Reference in New Issue
Block a user