hotfixes
This commit is contained in:
parent
b2c38e75bf
commit
71666d2891
6 changed files with 72 additions and 31 deletions
|
|
@ -193,29 +193,31 @@ export async function updateConnection(
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh Microsoft token
|
* Refresh Microsoft token
|
||||||
* Endpoint: POST /api/connections/{connectionId}/refresh-microsoft-token
|
* Endpoint: POST /api/msft/refresh
|
||||||
*/
|
*/
|
||||||
export async function refreshMicrosoftToken(
|
export async function refreshMicrosoftToken(
|
||||||
request: ApiRequestFunction,
|
request: ApiRequestFunction,
|
||||||
connectionId: string
|
connectionId: string
|
||||||
): Promise<Connection> {
|
): Promise<Connection> {
|
||||||
return await request({
|
return await request({
|
||||||
url: `/api/connections/${connectionId}/refresh-microsoft-token`,
|
url: '/api/msft/refresh',
|
||||||
method: 'post'
|
method: 'post',
|
||||||
|
data: { connectionId }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh Google token
|
* Refresh Google token
|
||||||
* Endpoint: POST /api/connections/{connectionId}/refresh-google-token
|
* Endpoint: POST /api/google/refresh
|
||||||
*/
|
*/
|
||||||
export async function refreshGoogleToken(
|
export async function refreshGoogleToken(
|
||||||
request: ApiRequestFunction,
|
request: ApiRequestFunction,
|
||||||
connectionId: string
|
connectionId: string
|
||||||
): Promise<Connection> {
|
): Promise<Connection> {
|
||||||
return await request({
|
return await request({
|
||||||
url: `/api/connections/${connectionId}/refresh-google-token`,
|
url: '/api/google/refresh',
|
||||||
method: 'post'
|
method: 'post',
|
||||||
|
data: { connectionId }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import React from 'react';
|
|
||||||
import { useLanguage } from '../../../providers/language/LanguageContext';
|
import { useLanguage } from '../../../providers/language/LanguageContext';
|
||||||
import styles from './FormGeneratorControls.module.css';
|
import styles from './FormGeneratorControls.module.css';
|
||||||
import { Button } from '../../UiComponents/Button';
|
import { Button } from '../../UiComponents/Button';
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { GenericPageData } from '../../pageInterface';
|
import { GenericPageData } from '../../pageInterface';
|
||||||
import { FaGoogle, FaMicrosoft, FaLink } from 'react-icons/fa';
|
import { FaGoogle, FaMicrosoft, FaLink, FaSync, FaPlug } from 'react-icons/fa';
|
||||||
import { useConnections } from '../../../../hooks/useConnections';
|
import { useConnections } from '../../../../hooks/useConnections';
|
||||||
|
|
||||||
// Helper function to convert attribute definitions to column config
|
// Helper function to convert attribute definitions to column config
|
||||||
|
|
@ -29,6 +29,8 @@ const createConnectionsHook = () => {
|
||||||
createGoogleConnectionAndAuth,
|
createGoogleConnectionAndAuth,
|
||||||
createMicrosoftConnectionAndAuth,
|
createMicrosoftConnectionAndAuth,
|
||||||
connectWithPopup,
|
connectWithPopup,
|
||||||
|
refreshMicrosoftToken,
|
||||||
|
refreshGoogleToken,
|
||||||
isConnecting,
|
isConnecting,
|
||||||
isLoading,
|
isLoading,
|
||||||
error,
|
error,
|
||||||
|
|
@ -92,9 +94,13 @@ const createConnectionsHook = () => {
|
||||||
connectWithPopup,
|
connectWithPopup,
|
||||||
createGoogleConnectionAndAuth,
|
createGoogleConnectionAndAuth,
|
||||||
createMicrosoftConnectionAndAuth,
|
createMicrosoftConnectionAndAuth,
|
||||||
|
// Token refresh operations
|
||||||
|
refreshMicrosoftToken,
|
||||||
|
refreshGoogleToken,
|
||||||
// Loading states
|
// Loading states
|
||||||
isConnecting,
|
isConnecting,
|
||||||
deletingConnections: new Set(), // Placeholder for consistency with other pages
|
deletingConnections: new Set(), // Placeholder for consistency with other pages
|
||||||
|
refreshingConnections: new Set<string>(), // Track which connections are refreshing
|
||||||
// Attributes and permissions for dynamic column/button generation
|
// Attributes and permissions for dynamic column/button generation
|
||||||
attributes,
|
attributes,
|
||||||
permissions,
|
permissions,
|
||||||
|
|
@ -192,28 +198,14 @@ export const connectionsPageData: GenericPageData = {
|
||||||
tableConfig: {
|
tableConfig: {
|
||||||
hookFactory: createConnectionsHook,
|
hookFactory: createConnectionsHook,
|
||||||
// Columns are generated dynamically from attributes via hookData.columns
|
// Columns are generated dynamically from attributes via hookData.columns
|
||||||
|
// Standard action buttons
|
||||||
actionButtons: [
|
actionButtons: [
|
||||||
{
|
|
||||||
type: 'connect',
|
|
||||||
title: 'connections.action.connect',
|
|
||||||
idField: 'id',
|
|
||||||
statusField: 'status',
|
|
||||||
operationName: 'connectWithPopup',
|
|
||||||
loadingStateName: 'isConnecting',
|
|
||||||
// Only show if user has update permission (connect = update operation)
|
|
||||||
disabled: (hookData: any) => {
|
|
||||||
if (!hookData?.permissions) return { disabled: false };
|
|
||||||
const hasUpdate = hookData.permissions.update !== 'n' && hookData.permissions.view;
|
|
||||||
return { disabled: !hasUpdate, message: 'No permission to connect' };
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
type: 'delete',
|
type: 'delete',
|
||||||
title: 'connections.action.delete',
|
title: 'connections.action.delete',
|
||||||
idField: 'id',
|
idField: 'id',
|
||||||
operationName: 'handleDelete',
|
operationName: 'handleDelete',
|
||||||
loadingStateName: 'deletingConnections',
|
loadingStateName: 'deletingConnections',
|
||||||
// Only show if user has delete permission
|
|
||||||
disabled: (hookData: any) => {
|
disabled: (hookData: any) => {
|
||||||
if (!hookData?.permissions) return { disabled: false };
|
if (!hookData?.permissions) return { disabled: false };
|
||||||
const hasDelete = hookData.permissions.delete !== 'n' && hookData.permissions.view;
|
const hasDelete = hookData.permissions.delete !== 'n' && hookData.permissions.view;
|
||||||
|
|
@ -221,6 +213,50 @@ export const connectionsPageData: GenericPageData = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
// Custom action buttons (entity-specific)
|
||||||
|
customActions: [
|
||||||
|
{
|
||||||
|
id: 'connect',
|
||||||
|
icon: React.createElement(FaPlug),
|
||||||
|
title: 'connections.action.connect',
|
||||||
|
onClick: async (row: any, hookData: any) => {
|
||||||
|
if (hookData?.connectWithPopup) {
|
||||||
|
await hookData.connectWithPopup(row.id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Only show connect button if status is not 'active'
|
||||||
|
visible: (row: any) => row.status !== 'active',
|
||||||
|
disabled: (_row: any, hookData: any) => {
|
||||||
|
if (!hookData?.permissions) return { disabled: false, message: '' };
|
||||||
|
const hasUpdate = hookData.permissions.update !== 'n' && hookData.permissions.view;
|
||||||
|
return { disabled: !hasUpdate, message: 'No permission to connect' };
|
||||||
|
},
|
||||||
|
loading: (_row: any, hookData: any) => hookData?.isConnecting || false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'refresh',
|
||||||
|
icon: React.createElement(FaSync),
|
||||||
|
title: 'connections.action.refresh',
|
||||||
|
onClick: async (row: any, hookData: any) => {
|
||||||
|
// Determine which refresh function to use based on authority
|
||||||
|
if (row.authority === 'msft' && hookData?.refreshMicrosoftToken) {
|
||||||
|
await hookData.refreshMicrosoftToken(row.id);
|
||||||
|
if (hookData?.refetch) await hookData.refetch();
|
||||||
|
} else if (row.authority === 'google' && hookData?.refreshGoogleToken) {
|
||||||
|
await hookData.refreshGoogleToken(row.id);
|
||||||
|
if (hookData?.refetch) await hookData.refetch();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Only show refresh button if status is 'active' (already connected)
|
||||||
|
visible: (row: any) => row.status === 'active',
|
||||||
|
disabled: (_row: any, hookData: any) => {
|
||||||
|
if (!hookData?.permissions) return { disabled: false, message: '' };
|
||||||
|
const hasUpdate = hookData.permissions.update !== 'n' && hookData.permissions.view;
|
||||||
|
return { disabled: !hasUpdate, message: 'No permission to refresh token' };
|
||||||
|
},
|
||||||
|
loading: (row: any, hookData: any) => hookData?.refreshingConnections?.has(row.id) || false
|
||||||
|
}
|
||||||
|
],
|
||||||
searchable: true,
|
searchable: true,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
|
|
|
||||||
|
|
@ -257,7 +257,7 @@ export const filesPageData: GenericPageData = {
|
||||||
await hookData.handleDownload(row.id, row.fileName, row.mimeType);
|
await hookData.handleDownload(row.id, row.fileName, row.mimeType);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
disabled: (row: any, hookData: any) => {
|
disabled: (_row: any, hookData: any) => {
|
||||||
if (!hookData?.permissions) return { disabled: false, message: '' };
|
if (!hookData?.permissions) return { disabled: false, message: '' };
|
||||||
const hasRead = hookData.permissions.read !== 'n' && hookData.permissions.view;
|
const hasRead = hookData.permissions.read !== 'n' && hookData.permissions.view;
|
||||||
return { disabled: !hasRead, message: 'No permission to download files' };
|
return { disabled: !hasRead, message: 'No permission to download files' };
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ export type PrivilegeChecker = () => boolean | Promise<boolean>;
|
||||||
export interface ButtonFormField {
|
export interface ButtonFormField {
|
||||||
key: string;
|
key: string;
|
||||||
label: string | LanguageText;
|
label: string | LanguageText;
|
||||||
type: 'string' | 'boolean' | 'email' | 'textarea' | 'date' | 'enum' | 'readonly' | 'multiselect';
|
type: 'string' | 'boolean' | 'email' | 'textarea' | 'date' | 'enum' | 'readonly' | 'multiselect' | 'number';
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
placeholder?: string | LanguageText;
|
placeholder?: string | LanguageText;
|
||||||
minRows?: number;
|
minRows?: number;
|
||||||
|
|
@ -17,6 +17,7 @@ export interface ButtonFormField {
|
||||||
validator?: (value: any) => string | null;
|
validator?: (value: any) => string | null;
|
||||||
defaultValue?: any;
|
defaultValue?: any;
|
||||||
options?: string[] | Array<{ value: string | number; label: string }>; // For enum/multiselect fields
|
options?: string[] | Array<{ value: string | number; label: string }>; // For enum/multiselect fields
|
||||||
|
optionsReference?: string; // Reference to a data source for dynamic options (e.g., 'TrusteeOrganisation', 'User')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dropdown configuration for header dropdown buttons
|
// Dropdown configuration for header dropdown buttons
|
||||||
|
|
@ -262,22 +263,26 @@ export interface GenericDataHook {
|
||||||
[key: string]: any; // Allow additional properties for dynamic data sources
|
[key: string]: any; // Allow additional properties for dynamic data sources
|
||||||
}
|
}
|
||||||
|
|
||||||
// Standard action button configuration (built-in actions: edit, delete, view, copy)
|
// Standard action button configuration (built-in actions: edit, delete, view, copy, connect, play)
|
||||||
export interface ActionButtonConfig {
|
export interface ActionButtonConfig {
|
||||||
type: 'view' | 'edit' | 'delete' | 'copy';
|
type: 'view' | 'edit' | 'delete' | 'copy' | 'connect' | 'play';
|
||||||
onAction?: (row: any) => Promise<void> | void; // Optional for delete buttons since they handle their own logic
|
onAction?: (row: any) => Promise<void> | void; // Optional for delete buttons since they handle their own logic
|
||||||
title?: string | LanguageText;
|
title?: string | LanguageText;
|
||||||
disabled?: (row: any) => boolean | { disabled: boolean; message?: string };
|
disabled?: (row: any, hookData?: any) => boolean | { disabled: boolean; message?: string };
|
||||||
loading?: (row: any) => boolean;
|
loading?: (row: any, hookData?: any) => boolean;
|
||||||
// Field mappings for flexible data access
|
// Field mappings for flexible data access
|
||||||
idField?: string; // Field name for the unique identifier (default: 'id')
|
idField?: string; // Field name for the unique identifier (default: 'id')
|
||||||
nameField?: string; // Field name for display name (default: 'name' or 'file_name')
|
nameField?: string; // Field name for display name (default: 'name' or 'file_name')
|
||||||
typeField?: string; // Field name for type/mime type (default: 'type' or 'mime_type')
|
typeField?: string; // Field name for type/mime type (default: 'type' or 'mime_type')
|
||||||
contentField?: string; // Field name for content (default: 'content')
|
contentField?: string; // Field name for content (default: 'content')
|
||||||
|
statusField?: string; // Field name for status (used by connect action)
|
||||||
// Operation and loading state names
|
// Operation and loading state names
|
||||||
operationName?: string; // Name of the operation function in hookData
|
operationName?: string; // Name of the operation function in hookData
|
||||||
loadingStateName?: string; // Name of the loading state in hookData
|
loadingStateName?: string; // Name of the loading state in hookData
|
||||||
fetchItemFunctionName?: string; // Name of the function in hookData to fetch a single item by ID (for edit button)
|
fetchItemFunctionName?: string; // Name of the function in hookData to fetch a single item by ID (for edit button)
|
||||||
|
// Navigation and mode (for play action)
|
||||||
|
navigateTo?: string; // Path to navigate to after action
|
||||||
|
mode?: string; // Mode to set (e.g., 'prompt', 'workflow')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom action button configuration (for entity-specific actions like download, connect, play, sendPasswordLink)
|
// Custom action button configuration (for entity-specific actions like download, connect, play, sendPasswordLink)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import { useState, useEffect, useCallback } from 'react';
|
import { useState, useEffect, useCallback } from 'react';
|
||||||
import { useApiRequest } from './useApi';
|
import { useApiRequest } from './useApi';
|
||||||
import { getUserDataCache } from '../utils/userCache';
|
|
||||||
import api from '../api';
|
import api from '../api';
|
||||||
import { usePermissions, type UserPermissions } from './usePermissions';
|
import { usePermissions, type UserPermissions } from './usePermissions';
|
||||||
import {
|
import {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue