1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-03 04:45:21 +02:00

feat(ask-ai): integrate kapa-ai page [BE-11409] (#214)

This commit is contained in:
Ali 2024-12-06 18:41:32 +13:00 committed by GitHub
parent 783ab253af
commit 441afead10
24 changed files with 102 additions and 50 deletions

View file

@ -1,6 +1,6 @@
import clsx from 'clsx';
import { PropsWithChildren } from 'react';
import type { Icon } from 'lucide-react';
import type { LucideIcon } from 'lucide-react';
import { TooltipWithChildren } from '@@/Tip/TooltipWithChildren';
@ -16,7 +16,7 @@ interface Props<T extends Value> {
tooltip?: string;
className?: string;
type?: 'radio' | 'checkbox';
checkIcon: Icon;
checkIcon: LucideIcon;
}
export function BoxOption<T extends Value>({

View file

@ -1,5 +1,5 @@
import clsx from 'clsx';
import { Icon as ReactFeatherComponentType, Check } from 'lucide-react';
import { type LucideIcon, Check } from 'lucide-react';
import { Fragment } from 'react';
import { Icon } from '@/react/components/Icon';
@ -22,7 +22,7 @@ type Props<T extends Value> = {
isSelected(value: T): boolean;
type?: 'radio' | 'checkbox';
slim?: boolean;
checkIcon?: ReactFeatherComponentType;
checkIcon?: LucideIcon;
};
export function BoxSelectorItem<T extends Value>({

View file

@ -1,6 +1,6 @@
import { ReactNode } from 'react';
import { useDocsUrl } from '../PageHeader/ContextHelp/ContextHelp';
import { useDocsUrl } from '@@/PageHeader/ContextHelp';
type HelpLinkProps = {
docLink: string;

View file

@ -0,0 +1,29 @@
import { BotMessageSquare } from 'lucide-react';
import clsx from 'clsx';
import headerStyles from './HeaderTitle.module.css';
const docsUrl = 'https://www.portainer.io/ask-the-ai';
export function AskAILink() {
return (
<div className={headerStyles.menuButton}>
<a
href={docsUrl}
target="_blank"
color="none"
className={clsx(
headerStyles.menuIcon,
'icon-badge mr-1 !p-2 text-lg cursor-pointer',
'text-gray-8',
'th-dark:text-gray-warm-7'
)}
title="Ask AI"
rel="noreferrer"
data-cy="ask-ai-button"
>
<BotMessageSquare className="lucide" />
</a>
</div>
);
}

View file

@ -4,8 +4,7 @@ import { useCurrentStateAndParams } from '@uirouter/react';
import { useSystemVersion } from '@/react/portainer/system/useSystemVersion';
import headerStyles from '../HeaderTitle.module.css';
import './ContextHelp.css';
import headerStyles from './HeaderTitle.module.css';
export function ContextHelp() {
const docsUrl = useDocsUrl();
@ -18,12 +17,11 @@ export function ContextHelp() {
color="none"
className={clsx(
headerStyles.menuIcon,
'menu-icon',
'icon-badge mr-1 !p-2 text-lg',
'icon-badge mr-1 !p-2 text-lg cursor-pointer',
'text-gray-8',
'th-dark:text-gray-warm-7'
)}
title="Help"
title="Documentation"
rel="noreferrer"
data-cy="context-help-button"
>

View file

@ -1,5 +0,0 @@
.menu-icon {
background: var(--user-menu-icon-color);
cursor: pointer;
flex-shrink: 0;
}

View file

@ -1 +0,0 @@
export { ContextHelp } from './ContextHelp';

View file

@ -10,6 +10,12 @@
.menu-icon {
background: var(--user-menu-icon-color);
position: relative;
flex-shrink: 0;
}
.menu-icon:hover {
/* keep the links and button icon colors consistent on hover */
@apply text-gray-8 th-dark:text-gray-warm-7;
}
.menu-list {

View file

@ -5,6 +5,7 @@ import { ContextHelp } from '@@/PageHeader/ContextHelp';
import { useHeaderContext } from './HeaderContainer';
import { NotificationsMenu } from './NotificationsMenu';
import { UserMenu } from './UserMenu';
import { AskAILink } from './AskAILink';
interface Props {
title: string;
@ -25,6 +26,7 @@ export function HeaderTitle({ title, children }: PropsWithChildren<Props>) {
{children && <>{children}</>}
</div>
<div className="flex items-end">
<AskAILink />
<NotificationsMenu />
<ContextHelp />
{!window.ddExtension && <UserMenu />}

View file

@ -1,7 +1,7 @@
import { ComponentProps } from 'react';
import { Alert } from '@@/Alert';
import { useDocsUrl } from '@@/PageHeader/ContextHelp/ContextHelp';
import { useDocsUrl } from '@@/PageHeader/ContextHelp';
import { EnvironmentVariablesFieldset } from './EnvironmentVariablesFieldset';
import { EnvironmentVariablesPanel } from './EnvironmentVariablesPanel';

View file

@ -2,7 +2,7 @@ import _ from 'lodash';
import {
AlertTriangle,
CheckCircle,
type Icon as IconType,
type LucideIcon,
Loader2,
XCircle,
MinusCircle,
@ -51,7 +51,7 @@ function getStatus(
hasOldVersion: boolean
): {
label: string;
icon?: IconType;
icon?: LucideIcon;
spin?: boolean;
mode?: IconMode;
tooltip?: string;

View file

@ -7,7 +7,7 @@ import { FormSectionTitle } from '@@/form-components/FormSectionTitle';
import { Input } from '@@/form-components/Input';
import { Button } from '@@/buttons';
import { TextTip } from '@@/Tip/TextTip';
import { useDocsUrl } from '@@/PageHeader/ContextHelp/ContextHelp';
import { useDocsUrl } from '@@/PageHeader/ContextHelp';
const initialValues = {
kubeConfig: '',

View file

@ -9,7 +9,7 @@ import { SwitchField } from '@@/form-components/SwitchField';
import { TextTip } from '@@/Tip/TextTip';
import { FormControl } from '@@/form-components/FormControl';
import { Input, Select } from '@@/form-components/Input';
import { useDocsUrl } from '@@/PageHeader/ContextHelp/ContextHelp';
import { useDocsUrl } from '@@/PageHeader/ContextHelp';
import { RelativePathModel, getPerDevConfigsFilterType } from './types';

View file

@ -1,8 +1,10 @@
import { useField } from 'formik';
import { SwitchField } from '@@/form-components/SwitchField';
import { useDocsUrl } from '@@/PageHeader/ContextHelp';
export function EnableTelemetryField() {
const privacyPolicy = useDocsUrl('/in-app-analytics-and-privacy-policy');
const [{ value }, , { setValue }] = useField<boolean>('enableTelemetry');
return (
@ -20,11 +22,7 @@ export function EnableTelemetryField() {
<div className="col-sm-12 text-muted small mt-2">
You can find more information about this in our{' '}
<a
href="https://www.portainer.io/documentation/in-app-analytics-and-privacy-policy/"
target="_blank"
rel="noreferrer"
>
<a href={privacyPolicy} target="_blank" rel="noreferrer">
privacy policy
</a>
.

View file

@ -3,7 +3,7 @@ import { useField, Field } from 'formik';
import { FormControl } from '@@/form-components/FormControl';
import { FormSection } from '@@/form-components/FormSection';
import { Input } from '@@/form-components/Input';
import { useDocsUrl } from '@@/PageHeader/ContextHelp/ContextHelp';
import { useDocsUrl } from '@@/PageHeader/ContextHelp';
// this value is taken from https://github.com/portainer/portainer/blob/develop/api/portainer.go#L1628
const DEFAULT_URL =

View file

@ -13,6 +13,7 @@ export interface VersionResponse {
// The latest version available
LatestVersion: string;
ServerVersion: string;
VersionSupport: 'STS' | 'LTS';
DatabaseVersion: string;
Build: {
BuildNumber: string;

View file

@ -23,22 +23,25 @@ import styles from './Footer.module.css';
export function BuildInfoModalButton() {
const [isBuildInfoVisible, setIsBuildInfoVisible] = useState(false);
const statusQuery = useSystemStatus();
const versionQuery = useSystemVersion();
if (!statusQuery.data) {
if (!statusQuery.data || !versionQuery.data) {
return null;
}
const { Version } = statusQuery.data;
const { VersionSupport } = versionQuery.data;
return (
<>
<button
type="button"
data-cy="portainerSidebar-versionNumber"
className="btn-none"
className="btn-none hover:underline"
onClick={() => setIsBuildInfoVisible(true)}
title="About Portainer"
>
{Version}
{`${Version} (${VersionSupport})`}
</button>
{isBuildInfoVisible && (
<BuildInfoModal closeModal={() => setIsBuildInfoVisible(false)} />
@ -57,8 +60,14 @@ function BuildInfoModal({ closeModal }: { closeModal: () => void }) {
}
const { Edition } = statusQuery.data;
const { ServerVersion, DatabaseVersion, Build, Dependencies, Runtime } =
versionQuery.data;
const {
ServerVersion,
DatabaseVersion,
Build,
Dependencies,
Runtime,
VersionSupport,
} = versionQuery.data;
return (
<Modal onDismiss={closeModal} aria-label="build-info-modal">
@ -69,13 +78,13 @@ function BuildInfoModal({ closeModal }: { closeModal: () => void }) {
<tbody>
<tr>
<td>
<span className="inline-flex items-center">
<span className="inline-flex items-center flex-wrap">
<Server size="13" className="space-right" />
Server Version: {ServerVersion}
Server Version: {ServerVersion} ({VersionSupport})
</span>
</td>
<td>
<span className="inline-flex items-center">
<span className="inline-flex items-center flex-wrap">
<Database size="13" className="space-right" />
Database Version: {DatabaseVersion}
</span>
@ -83,13 +92,13 @@ function BuildInfoModal({ closeModal }: { closeModal: () => void }) {
</tr>
<tr>
<td>
<span className="inline-flex items-center">
<span className="inline-flex items-center flex-wrap">
<Hash size="13" className="space-right" />
CI Build Number: {Build.BuildNumber}
</span>
</td>
<td>
<span>
<span className="inline-flex items-center flex-wrap">
<Tag size="13" className="space-right" />
Image Tag: {Build.ImageTag}
</span>
@ -97,8 +106,10 @@ function BuildInfoModal({ closeModal }: { closeModal: () => void }) {
</tr>
<tr>
<td>
<GitCommit size="13" className="space-right" />
Git Commit: {Build.GitCommit}
<span className="inline-flex items-center flex-wrap">
<GitCommit size="13" className="space-right" />
Git Commit: {Build.GitCommit}
</span>
</td>
<td />
</tr>

View file

@ -205,7 +205,7 @@ export function SettingsSidebar({ isPureAdmin, isAdmin, isTeamLeader }: Props) {
data-cy="portainerSidebar-edgeCompute"
/>
<SidebarItem.Wrapper label="Help / About">
<SidebarItem.Wrapper label="Get Help">
<a
href={
process.env.PORTAINER_EDITION === 'CE'
@ -216,7 +216,7 @@ export function SettingsSidebar({ isPureAdmin, isAdmin, isTeamLeader }: Props) {
rel="noreferrer"
className="hover:!underline focus:no-underline text-sm flex h-8 w-full items-center rounded px-3 transition-colors duration-200 hover:bg-blue-5/20 be:hover:bg-gray-5/20 th-dark:hover:bg-gray-true-5/20"
>
Help / About
Get Help
</a>
</SidebarItem.Wrapper>
</SidebarParent>

View file

@ -1,5 +1,5 @@
import { Meta, Story } from '@storybook/react';
import { Clock, Icon } from 'lucide-react';
import { Clock, type LucideIcon } from 'lucide-react';
import { SidebarItem } from '.';
@ -10,7 +10,7 @@ const meta: Meta = {
export default meta;
interface StoryProps {
icon?: Icon;
icon?: LucideIcon;
label: string;
}

View file

@ -1,4 +1,4 @@
import { Icon as IconTest } from 'lucide-react';
import { type LucideIcon } from 'lucide-react';
import clsx from 'clsx';
import { MouseEventHandler, PropsWithChildren } from 'react';
@ -13,7 +13,7 @@ import { SidebarTooltip } from './SidebarTooltip';
import { useSidebarSrefActive } from './useSidebarSrefActive';
interface Props extends AutomationTestingProps {
icon?: IconTest;
icon?: LucideIcon;
to: string;
params?: object;
label: string;