t0ng7u d146e45e2f ⚖️ chore(web/default): add reusable copyright header tooling
Add a Bun script to apply and normalize AGPL copyright headers across the default frontend source files.

The script keeps headers idempotent, upgrades existing headers to the 2023-2026 QuantumNous range, and is exposed through `bun run copyright` for future maintenance.
2026-05-09 11:35:07 +08:00

173 lines
4.2 KiB
TypeScript
Vendored

/*
Copyright (C) 2023-2026 QuantumNous
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
'use client'
import {
type ComponentProps,
createContext,
type ReactNode,
useContext,
} from 'react'
import type { ToolUIPart } from 'ai'
import { cn } from '@/lib/utils'
import { Alert, AlertDescription } from '@/components/ui/alert'
import { Button } from '@/components/ui/button'
// Workaround for missing types in 'ai' package
type ExtendedToolState =
| ToolUIPart['state']
| 'approval-requested'
| 'approval-responded'
| 'output-denied'
type ExtendedToolApproval = { approved: boolean }
type ConfirmationContextValue = {
approval: ExtendedToolApproval | undefined
state: ExtendedToolState
}
const ConfirmationContext = createContext<ConfirmationContextValue | null>(null)
const useConfirmation = () => {
const context = useContext(ConfirmationContext)
if (!context) {
throw new Error('Confirmation components must be used within Confirmation')
}
return context
}
export type ConfirmationProps = ComponentProps<typeof Alert> & {
approval?: ExtendedToolApproval
state: ExtendedToolState
}
export const Confirmation = ({
className,
approval,
state,
...props
}: ConfirmationProps) => {
if (!approval || state === 'input-streaming' || state === 'input-available') {
return null
}
return (
<ConfirmationContext.Provider value={{ approval, state }}>
<Alert className={cn('flex flex-col gap-2', className)} {...props} />
</ConfirmationContext.Provider>
)
}
export type ConfirmationTitleProps = ComponentProps<typeof AlertDescription>
export const ConfirmationTitle = ({
className,
...props
}: ConfirmationTitleProps) => (
<AlertDescription className={cn('inline', className)} {...props} />
)
export type ConfirmationRequestProps = {
children?: ReactNode
}
export const ConfirmationRequest = ({ children }: ConfirmationRequestProps) => {
const { state } = useConfirmation()
// Only show when approval is requested
if (state !== 'approval-requested') {
return null
}
return children
}
export type ConfirmationAcceptedProps = {
children?: ReactNode
}
export const ConfirmationAccepted = ({
children,
}: ConfirmationAcceptedProps) => {
const { approval, state } = useConfirmation()
// Only show when approved and in response states
if (
!approval?.approved ||
(state !== 'approval-responded' &&
state !== 'output-denied' &&
state !== 'output-available')
) {
return null
}
return children
}
export type ConfirmationRejectedProps = {
children?: ReactNode
}
export const ConfirmationRejected = ({
children,
}: ConfirmationRejectedProps) => {
const { approval, state } = useConfirmation()
// Only show when rejected and in response states
if (
approval?.approved !== false ||
(state !== 'approval-responded' &&
state !== 'output-denied' &&
state !== 'output-available')
) {
return null
}
return children
}
export type ConfirmationActionsProps = ComponentProps<'div'>
export const ConfirmationActions = ({
className,
...props
}: ConfirmationActionsProps) => {
const { state } = useConfirmation()
// Only show when approval is requested
if (state !== 'approval-requested') {
return null
}
return (
<div
className={cn('flex items-center justify-end gap-2 self-end', className)}
{...props}
/>
)
}
export type ConfirmationActionProps = ComponentProps<typeof Button>
export const ConfirmationAction = (props: ConfirmationActionProps) => (
<Button className='h-8 px-3 text-sm' type='button' {...props} />
)