Skip to content

Commit

Permalink
feat: set logo config in assistant
Browse files Browse the repository at this point in the history
Signed-off-by: tygao <tygao@amazon.com>
  • Loading branch information
raintygao committed Jan 22, 2025
1 parent 7858c95 commit f4a9579
Show file tree
Hide file tree
Showing 10 changed files with 71 additions and 14 deletions.
7 changes: 6 additions & 1 deletion common/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ export const configSchema = schema.object({
}),
branding: schema.object({
label: schema.maybe(schema.string()),
logo: schema.maybe(schema.string()),
logo: schema.maybe(
schema.object({
gradient: schema.maybe(schema.string()),
gray: schema.maybe(schema.string()),
})
),
}),
});

Expand Down
9 changes: 9 additions & 0 deletions public/chat_header_button.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { MountWrapper } from '../../../src/core/public/utils';
let mockSend: jest.Mock;
let mockLoadChat: jest.Mock;
let mockIncontextInsightRegistry: jest.Mock;
let mockGetConfigSchema: jest.Mock;

jest.mock('./hooks/use_chat_actions', () => {
mockSend = jest.fn();
Expand Down Expand Up @@ -43,8 +44,16 @@ jest.mock('./services', () => {
on: jest.fn(),
off: jest.fn(),
});
mockGetConfigSchema = jest.fn().mockReturnValue({
branding: {
logo: {
gray: '',
},
},
});
return {
getIncontextInsightRegistry: mockIncontextInsightRegistry,
getConfigSchema: mockGetConfigSchema,
};
});

Expand Down
11 changes: 8 additions & 3 deletions public/chat_header_button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
import { useCore } from './contexts/core_context';
import { MountPointPortal } from '../../../src/plugins/opensearch_dashboards_react/public';
import { usePatchFixedStyle } from './hooks/use_patch_fixed_style';
import { getConfigSchema } from './services';

interface HeaderChatButtonProps {
application: ApplicationStart;
Expand All @@ -49,7 +50,7 @@ export const HeaderChatButton = (props: HeaderChatButtonProps) => {
const [inputFocus, setInputFocus] = useState(false);
const inputRef = useRef<HTMLInputElement>(null);
const registry = getIncontextInsightRegistry();

const config = getConfigSchema();
const [sidecarDockedMode, setSidecarDockedMode] = useState(DEFAULT_SIDECAR_DOCKED_MODE);
const core = useCore();
const flyoutFullScreen = sidecarDockedMode === SIDECAR_DOCKED_MODE.TAKEOVER;
Expand All @@ -61,6 +62,10 @@ export const HeaderChatButton = (props: HeaderChatButtonProps) => {
return () => subscription.unsubscribe();
});

const logoIcon = useMemo(() => {
return config?.branding?.logo?.gray ?? chatIcon;
}, [config]);

const chatContextValue: IChatContext = useMemo(
() => ({
appId,
Expand Down Expand Up @@ -229,8 +234,8 @@ export const HeaderChatButton = (props: HeaderChatButtonProps) => {
prepend={
<EuiIcon
aria-label="toggle chat flyout icon"
type={chatIcon}
size="l"
type={logoIcon}
size="m"
onClick={() => setFlyoutVisible(!flyoutVisible)}
/>
}
Expand Down
12 changes: 9 additions & 3 deletions public/components/incontext_insight/generate_popover_body.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

import React, { useEffect, useState } from 'react';
import React, { useEffect, useState, useMemo } from 'react';
import { i18n } from '@osd/i18n';
import {
EuiFlexGroup,
Expand Down Expand Up @@ -33,14 +33,16 @@ import { buildUrlQuery, createIndexPatterns, extractTimeRangeDSL } from '../../u
import { AssistantPluginStartDependencies } from '../../types';
import { UI_SETTINGS } from '../../../../../src/plugins/data/public';
import { formatUrlWithWorkspaceId } from '../../../../../src/core/public/utils';
import { ConfigSchema } from '../../../common/types/config';

export const GeneratePopoverBody: React.FC<{
incontextInsight: IncontextInsightInput;
httpSetup?: HttpSetup;
usageCollection?: UsageCollectionSetup;
closePopover: () => void;
getStartServices?: StartServicesAccessor<AssistantPluginStartDependencies>;
}> = ({ incontextInsight, httpSetup, usageCollection, closePopover, getStartServices }) => {
config?: ConfigSchema;
}> = ({ incontextInsight, httpSetup, usageCollection, closePopover, getStartServices, config }) => {
const [summary, setSummary] = useState('');
const [insight, setInsight] = useState('');
const [contextObject, setContextObject] = useState<ContextObj | undefined>(undefined);
Expand All @@ -53,6 +55,10 @@ export const GeneratePopoverBody: React.FC<{

const [displayDiscoverButton, setDisplayDiscoverButton] = useState(false);

const logoIcon = useMemo(() => {
return config?.branding?.logo?.gradient ?? shiny_sparkle;
}, [config]);

useEffect(() => {
const getMonitorType = async () => {
if (!contextObject) return;
Expand Down Expand Up @@ -297,7 +303,7 @@ export const GeneratePopoverBody: React.FC<{
color={'text'}
/>
) : (
<EuiIcon aria-label="alert-assistant" color="hollow" size="l" type={shiny_sparkle} />
<EuiIcon aria-label="alert-assistant" color="hollow" size="m" type={logoIcon} />
)}
</EuiFlexItem>
<EuiFlexItem>
Expand Down
14 changes: 11 additions & 3 deletions public/components/incontext_insight/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
EuiWrappingPopover,
keys,
} from '@elastic/eui';
import React, { Children, isValidElement, useEffect, useRef, useState } from 'react';
import React, { Children, isValidElement, useEffect, useMemo, useRef, useState } from 'react';
import { IncontextInsight as IncontextInsightInput } from '../../types';
import { getIncontextInsightRegistry, getNotifications } from '../../services';
// TODO: Replace with getChrome().logos.Chat.url
Expand All @@ -35,12 +35,14 @@ import { HttpSetup, StartServicesAccessor } from '../../../../../src/core/public
import { GeneratePopoverBody } from './generate_popover_body';
import { UsageCollectionSetup } from '../../../../../src/plugins/usage_collection/public/plugin';
import { AssistantPluginStartDependencies } from '../../types';
import { ConfigSchema } from '../../../common/types/config';

export interface IncontextInsightProps {
children?: React.ReactNode;
httpSetup?: HttpSetup;
usageCollection?: UsageCollectionSetup;
getStartServices?: StartServicesAccessor<AssistantPluginStartDependencies>;
config?: ConfigSchema;
}

// TODO: add saved objects / config to store seed suggestions
Expand All @@ -49,6 +51,7 @@ export const IncontextInsight = ({
httpSetup,
usageCollection,
getStartServices,
config,
}: IncontextInsightProps) => {
const anchor = useRef<HTMLDivElement>(null);
const [isVisible, setIsVisible] = useState(false);
Expand Down Expand Up @@ -88,6 +91,10 @@ export const IncontextInsight = ({
}
}, []);

const logoIcon = useMemo(() => {
return config?.branding?.logo?.gradient ?? chatIcon;
}, [config]);

const registry = getIncontextInsightRegistry();
const toasts = getNotifications().toasts;
let target: React.ReactNode;
Expand Down Expand Up @@ -270,7 +277,7 @@ export const IncontextInsight = ({
</EuiFlexItem>
<EuiFlexItem grow={1}>
<div className="incontextInsightAnchorIcon">
<EuiIcon type={input.type === 'generate' ? sparkle : chatIcon} size="l" />
<EuiIcon type={logoIcon} size="m" />
</div>
</EuiFlexItem>
</EuiFlexGroup>
Expand All @@ -291,6 +298,7 @@ export const IncontextInsight = ({
usageCollection={usageCollection}
closePopover={closePopover}
getStartServices={getStartServices}
config={config}
/>
);
case 'summary':
Expand Down Expand Up @@ -324,7 +332,7 @@ export const IncontextInsight = ({
<EuiFlexGroup gutterSize="none">
<EuiFlexItem>
<div>
<EuiBadge color="hollow" iconType={chatIcon} iconSide="left">
<EuiBadge color="hollow" iconType={logoIcon} iconSide="left">
{i18n.translate('assistantDashboards.incontextInsight.assistant', {
defaultMessage: 'OpenSearch Assistant',
})}
Expand Down
8 changes: 6 additions & 2 deletions public/components/visualization/text2viz.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ export const Text2Viz = () => {
}
}, [editorInput]);

const logoIcon = useMemo(() => {
return config?.branding?.logo?.gray ?? chatIcon;
}, [config]);

/**
* The index pattern of current generated visualization used
*/
Expand Down Expand Up @@ -416,7 +420,7 @@ export const Text2Viz = () => {
onChange={(e) => setInputQuestion(e.target.value)}
fullWidth
compressed
prepend={<EuiIcon type={config.branding.logo || chatIcon} />}
prepend={<EuiIcon type={logoIcon} />}
placeholder="Generate visualization with a natural language question."
onKeyDown={(e) => e.key === 'Enter' && onSubmit()}
disabled={!selectedSource}
Expand Down Expand Up @@ -496,7 +500,7 @@ export const Text2Viz = () => {
) : null}
<EuiFlexItem className="text2viz__vizStyleEditorContainer">
<VizStyleEditor
iconType={config.branding.logo || chatIcon}
iconType={logoIcon}
onApply={(instruction) => onSubmit(instruction)}
value={currentInstruction}
/>
Expand Down
1 change: 1 addition & 0 deletions public/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ export class AssistantPlugin
httpSetup={httpSetup}
usageCollection={setupDeps.usageCollection}
getStartServices={core.getStartServices}
config={this.config}
/>
);
},
Expand Down
12 changes: 12 additions & 0 deletions public/tabs/__tests__/chat_window_header.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ jest.mock('../../components/chat_window_header_title', () => {
return { ChatWindowHeaderTitle: () => <div>OpenSearch Assistant</div> };
});

jest.mock('../../services', () => {
return {
getConfigSchema: jest.fn().mockReturnValue({
branding: {
logo: {
gray: '',
},
},
}),
};
});

const setup = ({ selectedTabId }: { selectedTabId?: TabId } = {}) => {
const useChatContextMock = {
conversationId: '1',
Expand Down
4 changes: 3 additions & 1 deletion public/tabs/chat/messages/message_bubble.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ export const MessageBubble: React.FC<MessageBubbleProps> = React.memo((props) =>
props.message.type === 'output' &&
props.message.contentType === 'markdown';

const logoIcon = configSchema?.branding?.logo?.gradient ?? chatIcon;

const createAvatar = (iconType?: IconType) => {
if (iconType) {
return (
Expand All @@ -68,7 +70,7 @@ export const MessageBubble: React.FC<MessageBubbleProps> = React.memo((props) =>
/>
);
} else {
return <EuiIcon type={chatIcon} size="l" />;
return <EuiIcon type={logoIcon} size="l" />;
}
};

Expand Down
7 changes: 6 additions & 1 deletion public/tabs/chat_window_header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,15 @@ import { ChatWindowHeaderTitle } from '../components/chat_window_header_title';
import chatIcon from '../assets/chat.svg';
import { TAB_ID } from '../utils/constants';
import { SidecarIconMenu } from '../components/sidecar_icon_menu';
import { getConfigSchema } from '../services';

export const ChatWindowHeader = React.memo(() => {
const chatContext = useChatContext();

const configSchema = getConfigSchema();

const logoIcon = configSchema?.branding?.logo?.gradient ?? chatIcon;

return (
<>
<EuiFlexGroup
Expand All @@ -26,7 +31,7 @@ export const ChatWindowHeader = React.memo(() => {
<EuiFlexItem>
<EuiFlexGroup gutterSize="none" alignItems="center" responsive={false}>
<EuiFlexItem grow={false} style={{ marginLeft: '8px' }}>
<EuiIcon type={chatIcon} size="m" />
<EuiIcon type={logoIcon} size="m" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<ChatWindowHeaderTitle />
Expand Down

0 comments on commit f4a9579

Please sign in to comment.