mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-14 01:50:39 +09:00
feat(plugin): scope secret-ref config by company
This commit is contained in:
parent
62863126a3
commit
db0ef46900
19 changed files with 587 additions and 102 deletions
|
|
@ -357,8 +357,10 @@ export const pluginsApi = {
|
|||
*
|
||||
* @param pluginId - UUID of the plugin.
|
||||
*/
|
||||
getConfig: (pluginId: string) =>
|
||||
api.get<PluginConfig | null>(`/plugins/${pluginId}/config`),
|
||||
getConfig: (pluginId: string, companyId?: string | null) => {
|
||||
const qs = companyId ? `?companyId=${encodeURIComponent(companyId)}` : "";
|
||||
return api.get<PluginConfig | null>(`/plugins/${pluginId}/config${qs}`);
|
||||
},
|
||||
|
||||
/**
|
||||
* Save (create or update) the configuration for a plugin.
|
||||
|
|
@ -369,8 +371,8 @@ export const pluginsApi = {
|
|||
* @param pluginId - UUID of the plugin.
|
||||
* @param configJson - Configuration values matching the plugin's `instanceConfigSchema`.
|
||||
*/
|
||||
saveConfig: (pluginId: string, configJson: Record<string, unknown>) =>
|
||||
api.post<PluginConfig>(`/plugins/${pluginId}/config`, { configJson }),
|
||||
saveConfig: (pluginId: string, configJson: Record<string, unknown>, companyId?: string | null) =>
|
||||
api.post<PluginConfig>(`/plugins/${pluginId}/config`, { configJson, companyId }),
|
||||
|
||||
/**
|
||||
* Call the plugin's `validateConfig` RPC method to test the configuration
|
||||
|
|
|
|||
|
|
@ -199,7 +199,8 @@ export const queryKeys = {
|
|||
detail: (pluginId: string) => ["plugins", pluginId] as const,
|
||||
health: (pluginId: string) => ["plugins", pluginId, "health"] as const,
|
||||
uiContributions: ["plugins", "ui-contributions"] as const,
|
||||
config: (pluginId: string) => ["plugins", pluginId, "config"] as const,
|
||||
config: (pluginId: string, companyId?: string | null) =>
|
||||
["plugins", pluginId, "config", companyId ?? null] as const,
|
||||
localFolders: (pluginId: string, companyId: string) =>
|
||||
["plugins", pluginId, "companies", companyId, "local-folders"] as const,
|
||||
dashboard: (pluginId: string) => ["plugins", pluginId, "dashboard"] as const,
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ import {
|
|||
* - `GET /api/plugins/:pluginId/health` — health diagnostics (polling).
|
||||
* Only fetched when `plugin.status === "ready"`.
|
||||
* - `GET /api/plugins/:pluginId/dashboard` — aggregated runtime dashboard data (polling).
|
||||
* - `GET /api/plugins/:pluginId/config` — current config values.
|
||||
* - `POST /api/plugins/:pluginId/config` — save config values.
|
||||
* - `GET /api/plugins/:pluginId/config?companyId=...` — current company config values.
|
||||
* - `POST /api/plugins/:pluginId/config` — save company config values.
|
||||
* - `POST /api/plugins/:pluginId/config/test` — test configuration.
|
||||
*
|
||||
* URL params:
|
||||
|
|
@ -97,9 +97,9 @@ export function PluginSettings() {
|
|||
const hasConfigSchema = configSchema && configSchema.properties && Object.keys(configSchema.properties).length > 0;
|
||||
|
||||
const { data: configData, isLoading: configLoading } = useQuery({
|
||||
queryKey: queryKeys.plugins.config(pluginId!),
|
||||
queryFn: () => pluginsApi.getConfig(pluginId!),
|
||||
enabled: !!pluginId && !!hasConfigSchema,
|
||||
queryKey: queryKeys.plugins.config(pluginId!, selectedCompanyId),
|
||||
queryFn: () => pluginsApi.getConfig(pluginId!, selectedCompanyId),
|
||||
enabled: !!pluginId && !!hasConfigSchema && !!selectedCompanyId,
|
||||
});
|
||||
|
||||
const { slots } = usePluginSlots({
|
||||
|
|
@ -245,6 +245,7 @@ export function PluginSettings() {
|
|||
) : hasConfigSchema ? (
|
||||
<PluginConfigForm
|
||||
pluginId={pluginId!}
|
||||
companyId={selectedCompanyId}
|
||||
schema={configSchema!}
|
||||
initialValues={configData?.configJson}
|
||||
isLoading={configLoading}
|
||||
|
|
@ -919,6 +920,7 @@ function isLikelyAbsolutePath(pathValue: string) {
|
|||
|
||||
interface PluginConfigFormProps {
|
||||
pluginId: string;
|
||||
companyId?: string | null;
|
||||
schema: JsonSchemaNode;
|
||||
initialValues?: Record<string, unknown>;
|
||||
isLoading?: boolean;
|
||||
|
|
@ -935,7 +937,7 @@ interface PluginConfigFormProps {
|
|||
* Separated from PluginSettings to isolate re-render scope — only the form
|
||||
* re-renders on field changes, not the entire page.
|
||||
*/
|
||||
function PluginConfigForm({ pluginId, schema, initialValues, isLoading, pluginStatus, supportsConfigTest }: PluginConfigFormProps) {
|
||||
function PluginConfigForm({ pluginId, companyId, schema, initialValues, isLoading, pluginStatus, supportsConfigTest }: PluginConfigFormProps) {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
// Form values: start with saved values, fall back to schema defaults
|
||||
|
|
@ -971,11 +973,11 @@ function PluginConfigForm({ pluginId, schema, initialValues, isLoading, pluginSt
|
|||
// Save mutation
|
||||
const saveMutation = useMutation({
|
||||
mutationFn: (configJson: Record<string, unknown>) =>
|
||||
pluginsApi.saveConfig(pluginId, configJson),
|
||||
pluginsApi.saveConfig(pluginId, configJson, companyId),
|
||||
onSuccess: () => {
|
||||
setSaveMessage({ type: "success", text: "Configuration saved." });
|
||||
setTestResult(null);
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.plugins.config(pluginId) });
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.plugins.config(pluginId, companyId) });
|
||||
// Clear success message after 3s
|
||||
setTimeout(() => setSaveMessage(null), 3000);
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue