Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
456 changes: 455 additions & 1 deletion Clients/package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Clients/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"@uppy/webcam": "^4.1.1",
"@uppy/xhr-upload": "^4.2.2",
"axios": "^1.12.0",
"cmdk": "^1.1.1",
"dayjs": "^1.11.13",
"dompurify": "^3.2.6",
"dotenv": "^16.4.7",
Expand Down
10 changes: 10 additions & 0 deletions Clients/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ import useUsers from "./application/hooks/useUsers";
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { useLocation } from "react-router-dom";
import { DeploymentManager } from "./application/utils/deploymentHelpers";
import CommandPalette from "./presentation/components/CommandPalette";
import CommandPaletteErrorBoundary from "./presentation/components/CommandPalette/ErrorBoundary";
import useCommandPalette from "./application/hooks/useCommandPalette";

// Component to conditionally apply theme based on route
const ConditionalThemeWrapper = ({ children, mode }: { children: React.ReactNode; mode: string }) => {
Expand Down Expand Up @@ -55,6 +58,7 @@ function App() {
const { token, userRoleName, organizationId, userId } = useAuth();
const [alert, setAlert] = useState<AlertProps | null>(null);
const { users, refreshUsers } = useUsers();
const commandPalette = useCommandPalette();

useEffect(() => {
setShowAlertCallback((alertProps: AlertProps) => {
Expand Down Expand Up @@ -177,6 +181,12 @@ function App() {
onClick={() => setAlert(null)}
/>
)}
<CommandPaletteErrorBoundary>
<CommandPalette
open={commandPalette.isOpen}
onOpenChange={commandPalette.close}
/>
</CommandPaletteErrorBoundary>
<Routes>
{createRoutes(triggerSidebar, triggerSidebarReload)}
</Routes>
Expand Down
97 changes: 97 additions & 0 deletions Clients/src/application/commands/actionHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { CommandAction } from './types'
import { logEngine } from '../tools/log.engine'

export interface CommandActionHandlers {
navigate: (path: string) => void
modal: (modalType: string) => void
function: (funcName: string, params?: unknown) => void
filter: (filterConfig: unknown) => void
export: (exportType: string) => void
}

export class CommandActionHandler {
private handlers: CommandActionHandlers

constructor(handlers: CommandActionHandlers) {
this.handlers = handlers
}

execute(action: CommandAction): void {
try {
// Validate action structure
if (!action || !action.type) {
throw new Error('Invalid command action: missing action type')
}

switch (action.type) {
case 'navigate':
if (!action.payload || typeof action.payload !== 'string') {
throw new Error('Navigate action requires a valid path string')
}
this.handlers.navigate(action.payload)
break

case 'modal':
if (!action.payload || typeof action.payload !== 'string') {
throw new Error('Modal action requires a valid modal type string')
}
this.handlers.modal(action.payload)
break

case 'function':
if (!action.payload || typeof action.payload !== 'object') {
throw new Error('Function action requires a valid payload object')
}
const funcPayload = action.payload as { name: string; params?: unknown }
if (!funcPayload.name || typeof funcPayload.name !== 'string') {
throw new Error('Function action requires a valid function name')
}
this.handlers.function(funcPayload.name, funcPayload.params)
break

case 'filter':
if (action.payload === undefined) {
throw new Error('Filter action requires a payload')
}
this.handlers.filter(action.payload)
break

case 'export':
if (!action.payload || typeof action.payload !== 'string') {
throw new Error('Export action requires a valid export type string')
}
this.handlers.export(action.payload)
break

default:
throw new Error(`Unknown command action type: ${action.type}`)
}

// Log successful command execution
logEngine({
type: 'info',
message: `Command executed successfully: ${action.type}`,
details: { payload: action.payload }
})

} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'

// Log detailed error information
logEngine({
type: 'error',
message: `Command execution failed: ${action.type}`,
details: {
error: errorMessage,
payload: action.payload,
stack: error instanceof Error ? error.stack : undefined
}
})

// Re-throw error for component-level error handling
throw new Error(`Command execution failed: ${errorMessage}`)
}
}
}

export default CommandActionHandler
12 changes: 12 additions & 0 deletions Clients/src/application/commands/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Command Palette API exports
export { default as commandRegistry } from './registry'
export { default as CommandActionHandler } from './actionHandler'
export { default as useCommandPalette } from '../hooks/useCommandPalette'
export type {
Command,
CommandGroup,
CommandContext,
CommandRegistry,
CommandAction
} from './types'
export type { CommandActionHandlers } from './actionHandler'
Loading