Skip to content

Commit

Permalink
Merge pull request #81 from fhlavac/inscope
Browse files Browse the repository at this point in the history
feat(inscope): Inscope enhancements
  • Loading branch information
fhlavac authored Aug 20, 2024
2 parents 534e658 + 80d9a2e commit 0351d84
Show file tree
Hide file tree
Showing 33 changed files with 776 additions and 213 deletions.
14 changes: 13 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,18 @@
"react-hooks/exhaustive-deps": "warn",
"react/no-unescaped-entities": ["error", { "forbid": [">", "}"] }],
"spaced-comment": "error",
"use-isnan": "error"
"use-isnan": "error",
"no-restricted-imports": [
"error",
{
"paths": [
{
"name": "react-jss",
"importNames": ["createUseStyles"],
"message": "Do not import { createUseStyles } from 'react-jss'; Use { createVaStyles, defaultTheme } from '../VirtualAssistantTheme' instead!"
}
]
}
]
}
}
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ This repo contains React Virtual assistant implementation.
```
import * as React from 'react';
import { Text } from '@patternfly/react-core';
import { createUseStyles } from 'react-jss';
import { createVaStyles } from '../VirtualAssistantTheme';
// do not forget to export your component's interface
// always place the component's interface above the component itself in the code
export interface MyComponentProps {
text: String;
}
const useStyles = createUseStyles({
const useStyles = createVaStyles({
myText: {
fontFamily: 'monospace',
fontSize: 'var(--pf-v5-global--icon--FontSize--md)',
Expand Down
58 changes: 58 additions & 0 deletions cypress/component/Citations.cy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React from 'react';
import Citations, { CitationsProps } from '../../packages/module/src/Citations';

const testCitations: CitationsProps['citations'] = [
{
id: 'citation-1',
title: 'Understanding PatternFly Layouts',
content: 'Content explaining the use of various layouts in PatternFly.',
ouiaId: 'citation-1',
},
{
id: 'citation-2',
title: 'PatternFly Design Guidelines',
content: 'Content about design guidelines.',
ouiaId: 'citation-2',
},
{
id: 'citation-3',
title: 'Accessibility in PatternFly',
content: 'Content about accessibility practices.',
ouiaId: 'citation-3',
},
];

describe('Citations', () => {
it('renders expandable section with citations', () => {
cy.mount(<Citations citations={testCitations} toggleText="Show Citations" ouiaId="test-citations" />);

cy.get('[data-ouia-component-id="test-citations-expandable-section"]').should('have.length', 1);
cy.get('[data-ouia-component-id="test-citations-accordion"]').should('not.be.visible');
});

it('expands and displays citations on toggle', () => {
cy.mount(<Citations citations={testCitations} toggleText="Show Citations" ouiaId="test-citations" />);

cy.get('[data-ouia-component-id="test-citations-expandable-section"] button').first().click();
cy.get('[data-ouia-component-id="test-citations-accordion"]').should('be.visible');

cy.get('[data-ouia-component-id="citation-1-toggle"]').should('have.length', 1);
cy.get('[data-ouia-component-id="citation-2-toggle"]').should('have.length', 1);
cy.get('[data-ouia-component-id="citation-3-toggle"]').should('have.length', 1);
});

it('toggles citations within the accordion', () => {
cy.mount(<Citations citations={testCitations} toggleText="Show Citations" ouiaId="test-citations" />);

cy.get('[data-ouia-component-id="test-citations-expandable-section"] button').first().click();

cy.get('[data-ouia-component-id="citation-1-toggle"]').click();
cy.get('[data-ouia-component-id="citation-1-content"]').should('be.visible');

cy.get('[data-ouia-component-id="citation-2-toggle"]').click();
cy.get('[data-ouia-component-id="citation-1-content"]').should('be.visible');
cy.get('[data-ouia-component-id="citation-1-toggle"]').click();
cy.get('[data-ouia-component-id="citation-1-content"]').should('not.be.visible');
cy.get('[data-ouia-component-id="citation-2-content"]').should('be.visible');
});
});
23 changes: 19 additions & 4 deletions cypress/component/LoadingMessage.cy.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,32 @@
import React from 'react';
import LoadingMessage from '../../packages/module/src/LoadingMessage';
import GrinIcon from '@patternfly/react-icons/dist/js/icons/grin-icon';
import { ThemeProvider } from 'react-jss';
import GrinIcon from '@patternfly/react-icons/dist/dynamic/icons/grin-icon';
import LoadingMessage from '@patternfly/virtual-assistant/src/LoadingMessage';
import { VirtualAssistantProvider } from '@patternfly/virtual-assistant/src/VirtualAssistantContext';
import { defaultTheme } from '@patternfly/virtual-assistant/src/VirtualAssistantTheme';

describe('LoadingMessage', () => {
it('renders default loading message', () => {
cy.mount(<LoadingMessage />);
cy.mount(
<ThemeProvider theme={defaultTheme}>
<VirtualAssistantProvider assistantIcon={GrinIcon}>
<LoadingMessage />
</VirtualAssistantProvider>
</ThemeProvider>
);

cy.get('[data-test-id="assistant-loading-icon"]').should('have.length', 1);
cy.get('[data-test-id="assistant-loading-dots"]').should('have.length', 1);
})

it('renders custom loading message', () => {
cy.mount(<LoadingMessage icon={GrinIcon} />);
cy.mount(
<ThemeProvider theme={defaultTheme}>
<VirtualAssistantProvider assistantIcon={GrinIcon}>
<LoadingMessage icon={GrinIcon} />
</VirtualAssistantProvider>
</ThemeProvider>
);

cy.get('[data-test-id="assistant-loading-icon"]').should('have.length', 1);
cy.get('[data-test-id="assistant-loading-dots"]').should('have.length', 1);
Expand Down
37 changes: 26 additions & 11 deletions cypress/component/VirtualAssistant.cy.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,49 @@
import React from 'react';
import { CardHeader } from '@patternfly/react-core';
import VirtualAssistant from '../../packages/module/src/VirtualAssistant';

describe('VirtualAssistant', () => {
describe('VirtualAssistant', () => {
it('renders virtual assistant body', () => {
cy.mount(<VirtualAssistant />);

cy.get('[data-test-id="assistant-title"]').first().should('contain', 'Virtual Assistant');
cy.get('[data-ouia-component-id="VirtualAssistant-title"]').first().should('contain', 'Virtual Assistant');
cy.get('[data-test-id="assistant-text-input"]').first().should('have.attr', 'placeholder', 'Send a message...');
cy.get('[data-test-id="assistant-send-button"]').first().should('not.be.disabled');
})
});

it('renders a customized title and placeholder', () => {
cy.mount(<VirtualAssistant title="PatternFly assistant" inputPlaceholder="You can ask anything in here." />);

cy.get('[data-test-id="assistant-title"]').should('contain', 'PatternFly assistant');
cy.get('[data-ouia-component-id="VirtualAssistant-title"]').should('contain', 'PatternFly assistant');
cy.get('[data-test-id="assistant-text-input"]').should('have.attr', 'placeholder', 'You can ask anything in here.');
cy.get('[data-test-id="assistant-send-button"]').should('not.be.disabled');
})
});

it('listens to messages', () => {
cy.mount(<VirtualAssistant onChangeMessage={cy.stub().as('change')} onSendMessage={cy.stub().as('send')} />);

cy.get('[data-test-id="assistant-text-input"]').type('my message');
cy.get('[data-test-id="assistant-send-button"]').click();
cy.get('@change').should('have.been.called');
cy.get('@send').should('have.been.called');
})
});

it('renders header with disabled send button', () => {
cy.mount(<VirtualAssistant isSendButtonDisabled />);

cy.get('[data-test-id="assistant-send-button"]').should('be.disabled');
})
})
});

it('renders in full-page mode', () => {
cy.mount(<VirtualAssistant isFullPage title="Full Page Assistant" />);

cy.get('[data-ouia-component-id="VirtualAssistant-title"]').should('contain', 'Full Page Assistant');
cy.get('.fullPage').should('exist');
});

it('renders a custom header', () => {
cy.mount(<VirtualAssistant header={<CardHeader data-ouia-component-id="custom-header">Custom Header</CardHeader>} />);

cy.get('[data-ouia-component-id="custom-header"]').should('contain', 'Custom Header');
});
});
12 changes: 9 additions & 3 deletions cypress/component/VirtualAssistantAction.cy.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import React from 'react';
import { ThemeProvider } from 'react-jss';
import VirtualAssistantAction from '@patternfly/virtual-assistant/src/VirtualAssistantAction';
import { AngleDownIcon } from '@patternfly/react-icons';
import { defaultTheme } from '@patternfly/virtual-assistant/src/VirtualAssistantTheme';

describe('VirtualAssistantAction', () => {
it('renders assistant action', () => {
cy.mount(<VirtualAssistantAction aria-label="Minimize virtual assistant" onClick={cy.stub().as('action')}>
<AngleDownIcon/>
</VirtualAssistantAction>);
cy.mount(
<ThemeProvider theme={defaultTheme}>
<VirtualAssistantAction aria-label="Minimize virtual assistant" onClick={cy.stub().as('action')}>
<AngleDownIcon/>
</VirtualAssistantAction>
</ThemeProvider>
);
cy.get('[aria-label="Minimize virtual assistant"]').click();
cy.get('@action').should('have.been.called');
cy.get('.pf-v5-svg').should('exist');
Expand Down
4 changes: 2 additions & 2 deletions cypress/e2e/VirtualAssistant.spec.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ describe('Test the Virtual assistant docs page', () => {
cy.wait(1000);

cy.get('[data-test-id="assistant-example-message"]').should('contain', 'Last received message: ');
cy.get('[data-test-id="assistant-text-input"]').eq(2).type('my message');
cy.get('[data-test-id="assistant-send-button"]').eq(2).click({ force: true });
cy.get('[data-test-id="assistant-text-input"]').eq(5).type('my message');
cy.get('[data-test-id="assistant-send-button"]').eq(5).click({ force: true });
cy.get('[data-test-id="assistant-example-message"]').should('contain', 'Last received message: my message');
})

Expand Down
2 changes: 1 addition & 1 deletion packages/module/generate-index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ async function generateIndex(files) {

files.forEach(file => {
const name = file.replace('/index.ts', '').split('/').pop();
stream.write(`\nexport { default as ${name} } from './${name}';\n`);
name !== 'VirtualAssistantContext' && stream.write(`\nexport { default as ${name} } from './${name}';\n`);
stream.write(`export * from './${name}';\n`);
});
stream.end();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,36 @@ Virtual assistant lives in its own package [`@patternfly/virtual-assistant`](htt

# Virtual assistant

The virtual assistant extension contains implementation of the react virtual assistant.
The Virtual Assistant extension provides UI components for building a virtual assistant layout, leveraging the design system foundations of PatternFly. These components are React-based and contain no additional logic.

You can take advantage of either the default appearance provided or make advanced customizations through the component's API to make the virtual assistant meet your specific needs.



## Getting started

To use this extension in your project, ensure that you have the necessary packages installed and always use the latest versions:

```
// package.json
"dependencies": {
"@patternfly/patternfly": "^5.3.1",
"@patternfly/react-core": "^5.3.4",
"@patternfly/react-styles": "^5.3.1",
"@patternfly/virtual-assistant": "1.0.0-prerelease.9",
},
```
### Importing stylesheets
If you haven't done so already, import the required stylesheets in your application:

```
import '@patternfly/react-core/dist/styles/base.css';
import '@patternfly/patternfly/patternfly-addons.css';
```

---

## Contributions and feedback

If you notice a bug or have a suggestion for the virtual assistant, feel free to file an issue in our [GitHub repository](https://github.com/patternfly/virtual-assistant/issues)! Please make sure to check if there is already a pre-existing issue before creating a new issue.
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import VirtualAssistant from '@patternfly/virtual-assistant/dist/dynamic/VirtualAssistant';
import AssistantMessageEntry from '@patternfly/virtual-assistant/dist/dynamic/AssistantMessageEntry';

const noRadiusTheme = {
global: {
borderRadiusBubble: '0'
},
components: {
VirtualAssistant: {
card: {
borderRadius: '0',
},
textArea: {
borderRadius: "0",
}
},
AssistantMessageEntry: {
label: {
borderRadius: '0'
}
}
}
}

export const BasicExample: React.FunctionComponent = () => (
<VirtualAssistant theme={noRadiusTheme}>
<AssistantMessageEntry
// eslint-disable-next-line no-console
options={[ { title: "Option #1", props: { onClick: () => {console.log('This is an example of onClick event')} } }, { title: "Option #2" }, { title: "Option #3" } ]}
>
How may I help you today? Do you have some question for me?
</AssistantMessageEntry>
</VirtualAssistant>
);
Loading

0 comments on commit 0351d84

Please sign in to comment.