Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Playbooks summary assited by AI #1974

Open
wants to merge 26 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
13957f3
Adding AI integration to playbooks
crspeller Feb 13, 2024
99fce53
WIP
jespino Nov 21, 2024
2251a92
Improving the interface
jespino Dec 11, 2024
07238c3
Improving history of chat and bot selection
jespino Dec 11, 2024
d3c8292
Moving ai_modal to the right place in the directories structure
jespino Dec 11, 2024
7250eb2
Applying required updates on the UX
jespino Dec 18, 2024
f3bf1fb
Merge remote-tracking branch 'origin/master' into playbooks-ai
jespino Dec 18, 2024
67a7800
Updating UI for ai status modal
asaadmahmood Jan 5, 2025
c3c49ae
Adding the close button to the generate interface
jespino Jan 7, 2025
220055a
A couple of small fixes
jespino Jan 7, 2025
49dcf05
Fixing initial load of the bots
jespino Jan 7, 2025
5daf663
Using a modal inside a modal instead of a floating interface
jespino Jan 7, 2025
2301d62
updating ui
asaadmahmood Jan 8, 2025
63f67e6
Removing unnecesary code
jespino Jan 10, 2025
d842868
Fixing linter complains
jespino Jan 10, 2025
3e93d3c
Removing unnecesary code
jespino Jan 10, 2025
1e3d156
Removing more unnecesary changes
jespino Jan 10, 2025
bd8c6b8
fixing ci
jespino Jan 10, 2025
3ef6e53
Fixing ci
jespino Jan 10, 2025
b93eccf
more typesafety
jespino Jan 10, 2025
fc67290
feat: Add accessibility labels for version navigation buttons
jespino Jan 10, 2025
8f98aab
feat: Improve accessibility of AI modal with ARIA labels and roles
jespino Jan 10, 2025
4f76f1f
Fixing aria-labels
jespino Jan 10, 2025
5aa20c2
refactor: Extract setTimeout milliseconds to constants in ai_modal
jespino Jan 10, 2025
40b8e61
refactor: Reorganize imports and constants in ai_modal.tsx
jespino Jan 10, 2025
fc96f7d
Fixing linter errors
jespino Jan 12, 2025
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
189 changes: 96 additions & 93 deletions webapp/package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"dependencies": {
"@apollo/client": "3.7.3",
"@floating-ui/react-dom-interactions": "0.6.3",
"@mattermost/compass-icons": "0.1.32",
"@mattermost/compass-icons": "0.1.47",
"@mattermost/types": "7.1.0",
"@mdi/js": "^6.5.95",
"@mdi/react": "1.5.0",
Expand Down
2 changes: 1 addition & 1 deletion webapp/src/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ export function openUpdateRunStatusModal(
hasPermission: boolean,
message?: string,
reminderInSeconds?: number,
finishRunChecked?: boolean
finishRunChecked?: boolean,
) {
return modals.openModal(makeUpdateRunStatusModalDefinition({
playbookRunId,
Expand Down
36 changes: 36 additions & 0 deletions webapp/src/ai_integration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import {GlobalState} from 'mattermost-webapp/packages/types/src/store';
import {useSelector} from 'react-redux';

import {Bot, BotSelector, BotsLoaderHook} from './types/ai';

export const aiPluginID = 'mattermost-ai';

export const useAIAvailable = () => {
//@ts-ignore plugins state is a thing
return useSelector<GlobalState, boolean>((state) => Boolean(state.plugins?.plugins?.[aiPluginID]));
};

export const useAIAvailableBots = () => {
return useSelector<GlobalState, Bot[]>((state) => {
//@ts-ignore plugins state is a thing
return state['plugins-' + aiPluginID]?.bots || [];
});
};

export const useBotSelector = () => {
return useSelector<GlobalState, BotSelector>((state) => {
//@ts-ignore plugins state is a thing
return state['plugins-' + aiPluginID]?.botSelector;
});
};

export const useBotsLoaderHook = () => {
return useSelector<GlobalState, BotsLoaderHook>((state) => {
//@ts-ignore plugins state is a thing
return state['plugins-' + aiPluginID]?.botsLoaderHook || (() => null);
});
};

26 changes: 26 additions & 0 deletions webapp/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ export const setSiteUrl = (url?: string): void => {
apiUrl = `${basePath}/plugins/${manifest.id}/api/v0`;
};

function playbookRunRoute(playbookRunID: string): string {
return `${basePath}/plugins/mattermost-ai/playbook_run/${playbookRunID}`;
}

export const getSiteUrl = (): string => {
return siteURL;
};
Expand Down Expand Up @@ -811,3 +815,25 @@ export async function getTeamTopPlaybooks(timeRange: string, page: number, perPa
}
return data as InsightsResponse;
}

export async function generateStatusUpdate(playbookRunID: string, botId: string, instructions: string[], messages: string[]) {
const url = `${playbookRunRoute(playbookRunID)}/generate_status`;
const response = await fetch(url, Client4.getOptions({
method: 'POST',
body: JSON.stringify({
instructions,
messages,
bot: botId,
}),
}));

if (response.ok) {
return;
}

throw new ClientError(Client4.url, {
message: '',
status_code: response.status,
url,
});
}
25 changes: 25 additions & 0 deletions webapp/src/components/assets/buttons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,31 @@ export const InvertedTertiaryButton = styled(Button)`
}
`;

export const QuaternaryButton = styled(Button)`
transition: all 0.15s ease-out;

&& {
color: var(--center-channel-color-64);
background-color: rgba(var(--center-channel-color-rgb), 0.08);
}

&&:hover:not([disabled]) {
color: var(--center-channel-color-75);
background-color: rgba(var(--center-channel-color-rgb), 0.12);
}

&&:active:not([disabled]) {
color: var(--button-bg-rgb);
background: rgba(var(--button-bg-rgb), 0.16);
}

&&:focus:not([disabled]) {
color: var(--button-bg-rgb);
background-color: rgba(var(--button-color-rgb), 0.08);
box-shadow: inset 0px 0px 0px 2px var(--sidebar-text-active-border-rgb);
}
`;

export const SecondaryButton = styled(TertiaryButton)`
background: var(--button-color-rgb);
border: 1px solid var(--button-bg);
Expand Down
34 changes: 34 additions & 0 deletions webapp/src/components/assets/icons/ai.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';

import Svg from 'src/components/assets/svg';

interface Props {
size?: number;
}

const IconAI = ({size = 16}: Props) => (
<Svg
width={size}
height={size}
viewBox='0 0 19 19'
fill='none'
>
<path
fillRule='evenodd'
clipRule='evenodd'
d='M8.50453 8.70448L5.69986 9.5999L8.50453 10.4953L9.39995 13.3L10.2954 10.4953L13.1 9.5999L10.2954 8.70448L9.39995 5.89981L8.50453 8.70448ZM7.17355 7.3735L0.199951 9.5999L7.17355 11.8263L9.39995 18.7999L11.6264 11.8263L18.6 9.5999L11.6264 7.3735L9.39995 0.399902L7.17355 7.3735Z'
fill='currentColor'
/>
<path
d='M3.80005 2L3.36005 3.56L1.80005 4L3.36005 4.44L3.80005 6L4.24005 4.44L5.80005 4L4.24005 3.56L3.80005 2Z'
fill='currentColor'
/>
<path
d='M15.4 12.3999L14.696 14.8959L12.2 15.5999L14.696 16.3039L15.4 18.7999L16.104 16.3039L18.6 15.5999L16.104 14.8959L15.4 12.3999Z'
fill='currentColor'
/>
</Svg>

);

export default IconAI;
11 changes: 8 additions & 3 deletions webapp/src/components/markdown_textbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type Props = {
hideHelpBar?: boolean;
previewByDefault?: boolean;
autoFocus?: boolean;
minHeight?: string;
} & ComponentProps<typeof Textbox>;

const MarkdownTextbox = ({
Expand All @@ -48,6 +49,7 @@ const MarkdownTextbox = ({
previewByDefault,
autoFocus,
hideHelpBar,
minHeight = '104px',
...textboxProps
}: Props) => {
const [showPreview, setShowPreview] = useState(previewByDefault);
Expand All @@ -63,7 +65,10 @@ const MarkdownTextbox = ({
});

return (
<Wrapper className={className}>
<Wrapper
className={className}
$minHeight={minHeight}
>
<Textbox
tabIndex={0}
value={value}
Expand Down Expand Up @@ -96,7 +101,7 @@ const MarkdownTextbox = ({
);
};

const Wrapper = styled.div`
const Wrapper = styled.div<{$minHeight?: string}>`
.textarea-wrapper {
margin-bottom: 6px;
}
Expand All @@ -121,7 +126,7 @@ const Wrapper = styled.div`
}

height: unset;
min-height: 104px;
min-height: ${(props) => props.$minHeight || '104px'};
max-height: 324px;
overflow: auto;
padding: 12px 30px 12px 16px;
Expand Down
Loading
Loading