Skip to content

Commit 2cf0381

Browse files
authored
feat: add bot comments (#54)
* feat: add bot comments * feat: add ghost prompt for chatbot prompts * feat: add maximum comment length * feat: add chatbot prompt settings
1 parent 15fac2d commit 2cf0381

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1215
-194
lines changed

.github/workflows/cdelivery-s3-apps-caller.yml

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,30 @@ on:
66
repository_dispatch:
77
types: [staging-deployment]
88

9+
env:
10+
REACT_APP_OPEN_AI_API_URL: ${{ secrets.REACT_APP_OPEN_AI_API_URL_STAGE }}
11+
912
# This workflow is made up of one job that calls the reusable workflow in graasp-deploy
1013
jobs:
11-
graasp-deploy-s3-apps-workflow:
12-
# Replace with repository name
13-
name: Code Capsule App
14-
# Replace 'main' with the hash of a commit, so it points to an specific version of the reusable workflow that is used
15-
# Reference reusable workflow file. Using the commit SHA is the safest for stability and security
16-
uses: graasp/graasp-deploy/.github/workflows/cdelivery-s3-apps.yml@v1
17-
# Replace input build-folder or version if needed
18-
with:
19-
build-folder: 'build'
20-
version: 'latest'
21-
tag: ${{ github.event.client_payload.tag }}
22-
# Insert required secrets based on repository with the following format: ${{ secrets.SECRET_NAME }}
23-
secrets:
24-
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_STAGE }}
25-
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_STAGE }}
26-
aws-region: ${{ secrets.APPS_AWS_REGION }}
27-
aws-s3-bucket-name: ${{ secrets.AWS_S3_BUCKET_NAME_APPS_STAGE }}
28-
cloudfront-distribution-id: ${{ secrets.CLOUDFRONT_DISTRIBUTION_APPS_STAGE }}
29-
app-id: ${{ secrets.APP_ID }}
30-
graasp-domain: ${{ secrets.REACT_APP_DOMAIN_STAGE }}
31-
sentry-dsn: ${{ secrets.SENTRY_DSN }}
14+
deploy-app-to-staging:
15+
name: Deploy app to Staging
16+
runs-on: ubuntu-latest
17+
steps:
18+
# Replace with repository name
19+
- name: Code Capsule App
20+
# Replace 'main' with the hash of a commit, so it points to an specific version of the reusable workflow that is used
21+
# Reference reusable workflow file. Using the commit SHA is the safest for stability and security
22+
uses: graasp/graasp-deploy/.github/actions/deploy-stage-s3-apps@7184b0e664d2d9481167ae8788954dad99ab4ef6
23+
# Replace input build-folder or version if needed
24+
with:
25+
build-folder: 'build'
26+
version: 'latest'
27+
tag: ${{ github.event.client_payload.tag }}
28+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_STAGE }}
29+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_STAGE }}
30+
aws-region: ${{ secrets.APPS_AWS_REGION }}
31+
aws-s3-bucket-name: ${{ secrets.AWS_S3_BUCKET_NAME_APPS_STAGE }}
32+
cloudfront-distribution-id: ${{ secrets.CLOUDFRONT_DISTRIBUTION_APPS_STAGE }}
33+
app-id: ${{ secrets.APP_ID }}
34+
graasp-domain: ${{ secrets.REACT_APP_DOMAIN_STAGE }}
35+
sentry-dsn: ${{ secrets.SENTRY_DSN }}

.github/workflows/cdeployement-s3-apps-caller.yml

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,29 @@ on:
66
repository_dispatch:
77
types: [production-deployment]
88

9+
env:
10+
REACT_APP_OPEN_AI_API_URL: ${{ secrets.REACT_APP_OPEN_AI_API_URL_PROD }}
11+
912
# This workflow is made up of one job that calls the reusable workflow in graasp-deploy
1013
jobs:
11-
graasp-deploy-s3-apps-workflow:
12-
# Replace with repository name
13-
name: Code Capsule App
14-
# Replace 'main' with the hash of a commit, so it points to an specific version of the reusable workflow that is used
15-
# Reference reusable workflow file. Using the commit SHA is the safest for stability and security
16-
uses: graasp/graasp-deploy/.github/workflows/cdeployment-s3-apps.yml@v1
17-
# Replace input build-folder or version if needed.
18-
with:
19-
build-folder: 'build'
20-
version: 'latest'
21-
tag: ${{ github.event.client_payload.tag }}
22-
# Insert required secrets based on repository with the following format: ${{ secrets.SECRET_NAME }}
23-
secrets:
24-
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_PROD }}
25-
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_PROD }}
26-
aws-region: ${{ secrets.APPS_AWS_REGION }}
27-
aws-s3-bucket-name: ${{ secrets.AWS_S3_BUCKET_NAME_APPS_PROD }}
28-
cloudfront-distribution-id: ${{ secrets.CLOUDFRONT_DISTRIBUTION_APPS_PROD }}
29-
app-id: ${{ secrets.APP_ID }}
30-
graasp-domain: ${{ secrets.REACT_APP_DOMAIN_PROD }}
31-
sentry-dsn: ${{ secrets.SENTRY_DSN }}
14+
deploy-app-to-prod:
15+
name: Deploy app to Production
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Code Capsule App
19+
# Replace 'main' with the hash of a commit, so it points to an specific version of the reusable workflow that is used
20+
# Reference reusable workflow file. Using the commit SHA is the safest for stability and security
21+
uses: graasp/graasp-deploy/.github/actions/deploy-prod-s3-apps@0bd44afb246426b63ef6f312588a16f0063f6d92
22+
# Replace input build-folder or version if needed.
23+
with:
24+
build-folder: 'build'
25+
version: 'latest'
26+
tag: ${{ github.event.client_payload.tag }}
27+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_PROD }}
28+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_PROD }}
29+
aws-region: ${{ secrets.APPS_AWS_REGION }}
30+
aws-s3-bucket-name: ${{ secrets.AWS_S3_BUCKET_NAME_APPS_PROD }}
31+
cloudfront-distribution-id: ${{ secrets.CLOUDFRONT_DISTRIBUTION_APPS_PROD }}
32+
app-id: ${{ secrets.APP_ID }}
33+
graasp-domain: ${{ secrets.REACT_APP_DOMAIN_PROD }}
34+
sentry-dsn: ${{ secrets.SENTRY_DSN }}

.github/workflows/cintegration-s3-apps-caller.yml

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,25 @@ on:
1111
# Allows you to run this workflow manually from the Actions tab
1212
workflow_dispatch:
1313

14+
env:
15+
REACT_APP_OPEN_AI_API_URL: ${{ secrets.REACT_APP_OPEN_AI_API_URL_DEV }}
16+
1417
# This workflow is made up of one job that calls the reusable workflow in graasp-deploy
1518
jobs:
16-
graasp-deploy-s3-apps-workflow:
17-
name: Code Capsule App
18-
uses: graasp/graasp-deploy/.github/workflows/cintegration-s3-apps.yml@v1
19-
with:
20-
build-folder: 'build'
21-
version: 'latest'
22-
secrets:
23-
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_DEV }}
24-
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_DEV }}
25-
aws-region: ${{ secrets.APPS_AWS_REGION }}
26-
aws-s3-bucket-name: ${{ secrets.AWS_S3_BUCKET_NAME_APPS_DEV }}
27-
cloudfront-distribution-id: ${{ secrets.CLOUDFRONT_DISTRIBUTION_APPS_DEV }}
28-
app-id: ${{ secrets.APP_ID }}
29-
graasp-domain: ${{ secrets.REACT_APP_DOMAIN_DEV }}
30-
sentry-dsn: ${{ secrets.SENTRY_DSN }}
19+
deploy-app-to-dev:
20+
name: Deploy app to Development
21+
runs-on: ubuntu-latest
22+
steps:
23+
- name: Code Capsule App
24+
uses: graasp/graasp-deploy/.github/actions/deploy-dev-s3-apps@7010f99aa851465a150c71f8ffcc549c8fcd3582
25+
with:
26+
build-folder: 'build'
27+
version: 'latest'
28+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_DEV }}
29+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_DEV }}
30+
aws-region: ${{ secrets.APPS_AWS_REGION }}
31+
aws-s3-bucket-name: ${{ secrets.AWS_S3_BUCKET_NAME_APPS_DEV }}
32+
cloudfront-distribution-id: ${{ secrets.CLOUDFRONT_DISTRIBUTION_APPS_DEV }}
33+
app-id: ${{ secrets.APP_ID }}
34+
graasp-domain: ${{ secrets.REACT_APP_DOMAIN_DEV }}
35+
sentry-dsn: ${{ secrets.SENTRY_DSN }}

.github/workflows/cypress.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ jobs:
3030
REACT_APP_GRAASP_APP_ID: id-1234567890
3131
REACT_APP_MOCK_API: true
3232
NODE_ENV: test
33+
REACT_APP_OPEN_AI_API_URL: http://localhost:1234
3334
with:
3435
install: false
3536
build: yarn build

README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ This repository hosts the code for a Graasp app that lets users write code revie
1111

1212
Create a `.env.development` file with the following content:
1313

14-
```
14+
```bash
1515
PORT=3005
1616
CYPRESS_BASE_URL=http://localhost:3005
1717

@@ -20,13 +20,15 @@ REACT_APP_MOCK_API=true
2020
REACT_APP_API_HOST=http://localhost:3636
2121

2222
REACT_APP_VERSION=$npm_package_version
23+
24+
REACT_APP_OPEN_AI_API_URL=<url of the api>
2325
```
2426

2527
## Running the tests (automatic run on commit with husky)
2628

2729
Create a `.env.test` file with the following content:
2830

29-
```
31+
```bash
3032
PORT=3333
3133
CYPRESS_BASE_URL=http://localhost:3333
3234
CYPRESS_INSTRUMENT_PRODUCTION=true
@@ -35,6 +37,8 @@ REACT_APP_GRAASP_APP_ID=1234-1234
3537
REACT_APP_MOCK_API=true
3638
REACT_APP_API_HOST=http://localhost:3636
3739

40+
REACT_APP_OPEN_AI_API_URL=<url of the api>
41+
3842
BROWSER=none
3943
```
4044

@@ -64,4 +68,4 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
6468

6569
<!-- ALL-CONTRIBUTORS-LIST:END -->
6670

67-
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
71+
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!

cypress.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export default defineConfig({
44
video: true,
55

66
e2e: {
7-
retries: 2,
7+
retries: 1,
88
// We've imported your old cypress plugins here.
99
// You may want to clean this up later by importing these.
1010
setupNodeEvents(on, config) {

cypress/e2e/builder/manageAppResources.cy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ describe('Builder as Admin', () => {
7575
cy.get(buildDataCy(TAB_TABLE_VIEW_CYPRESS)).should('be.visible').click();
7676
});
7777

78-
it.only('should download AppActions', () => {
78+
it('should download AppActions', () => {
7979
// check that the table view pane is visible
8080
cy.get(buildDataCy(DOWNLOAD_ACTIONS_BUTTON_CY))
8181
.should('be.visible')
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import {
2+
CODE_REVIEW_CONTAINER_CYPRESS,
3+
COMMENT_CONTAINER_CYPRESS,
4+
COMMENT_EDITOR_SAVE_BUTTON_CYPRESS,
5+
COMMENT_EDITOR_TEXTAREA_CYPRESS,
6+
COMMENT_RESPONSE_BOX_CY,
7+
buildChatbotPromptContainerDataCy,
8+
buildCommentContainerDataCy,
9+
buildCommentResponseBoxDataCy,
10+
buildDataCy,
11+
} from '../../../src/config/selectors';
12+
import { CHATBOT_THREAD_MOCK_COMMENTS } from '../../fixtures/appData';
13+
import {
14+
CODE_REVIEW_MODE_SETTING,
15+
MOCK_CHATBOT_PROMPT_SETTINGS_INPUT,
16+
MOCK_CODE_SETTINGS,
17+
} from '../../fixtures/appSettings';
18+
19+
describe('OpenAI api chatbot', () => {
20+
describe('no previous interactions', () => {
21+
beforeEach(() => {
22+
cy.setUpApi({
23+
database: {
24+
appSettings: [
25+
// set the view to "code-review" mode
26+
CODE_REVIEW_MODE_SETTING,
27+
// set some code
28+
MOCK_CODE_SETTINGS,
29+
// chatbot prompt setting
30+
MOCK_CHATBOT_PROMPT_SETTINGS_INPUT,
31+
],
32+
},
33+
});
34+
cy.visit('/');
35+
});
36+
37+
it('show a ghost comment', () => {
38+
cy.get(buildDataCy(CODE_REVIEW_CONTAINER_CYPRESS)).should('be.visible');
39+
40+
// check that the bot comment is shown
41+
cy.get(
42+
buildDataCy(
43+
buildChatbotPromptContainerDataCy(
44+
MOCK_CHATBOT_PROMPT_SETTINGS_INPUT.id,
45+
),
46+
),
47+
).should('be.visible');
48+
49+
// click on the response box
50+
cy.get(
51+
buildDataCy(
52+
buildCommentResponseBoxDataCy(MOCK_CHATBOT_PROMPT_SETTINGS_INPUT.id),
53+
),
54+
).click();
55+
56+
cy.get(buildDataCy(COMMENT_EDITOR_TEXTAREA_CYPRESS)).type(
57+
'hello chatbot how are you ?',
58+
);
59+
60+
cy.get(buildDataCy(COMMENT_EDITOR_SAVE_BUTTON_CYPRESS)).click();
61+
62+
// wait for chatbot response to come
63+
cy.get(`[data-cy^=${COMMENT_CONTAINER_CYPRESS}]`).should(
64+
'have.length',
65+
3,
66+
);
67+
});
68+
});
69+
70+
describe('with previous interaction', () => {
71+
beforeEach(() => {
72+
cy.setUpApi({
73+
database: {
74+
appSettings: [
75+
// set the view to "code-review" mode
76+
CODE_REVIEW_MODE_SETTING,
77+
// set some code
78+
MOCK_CODE_SETTINGS,
79+
// chatbot prompt setting
80+
MOCK_CHATBOT_PROMPT_SETTINGS_INPUT,
81+
],
82+
appData: [
83+
// chatbot thread
84+
...CHATBOT_THREAD_MOCK_COMMENTS,
85+
],
86+
},
87+
});
88+
cy.visit('/');
89+
});
90+
91+
it('show chatbot thread', () => {
92+
cy.get(buildDataCy(CODE_REVIEW_CONTAINER_CYPRESS)).should('be.visible');
93+
94+
// check that the first comment is displayed
95+
cy.get(
96+
buildDataCy(
97+
buildCommentContainerDataCy(CHATBOT_THREAD_MOCK_COMMENTS[0].id),
98+
),
99+
).should('be.visible');
100+
cy.get(buildDataCy(COMMENT_RESPONSE_BOX_CY)).click();
101+
cy.get(buildDataCy(COMMENT_EDITOR_TEXTAREA_CYPRESS)).type('test');
102+
cy.get(buildDataCy(COMMENT_EDITOR_SAVE_BUTTON_CYPRESS)).click();
103+
});
104+
});
105+
});

cypress/e2e/codeReview/codeReview.cy.ts

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
COMMENT_EDITOR_LINE_INFO_TEXT_CYPRESS,
1515
COMMENT_EDITOR_SAVE_BUTTON_CYPRESS,
1616
COMMENT_EDITOR_TEXTAREA_CYPRESS,
17+
COMMENT_EDITOR_TEXTAREA_HELPER_TEXT_CY,
1718
COMMENT_THREAD_CONTAINER_CYPRESS,
1819
COMMIT_INFO_DIALOG_CYPRESS,
1920
CUSTOM_DIALOG_TITLE_CYPRESS,
@@ -169,7 +170,7 @@ describe('Code Review thread comments', () => {
169170
.should('have.length', 2)
170171
.each((el, i) => {
171172
cy.wrap(el)
172-
.children(buildDataCy(COMMENT_CONTAINER_CYPRESS))
173+
.children(`[data-cy^=${COMMENT_CONTAINER_CYPRESS}]`)
173174
.should('have.length', threadOptions[i].threadLength);
174175
});
175176
});
@@ -218,16 +219,16 @@ describe('Code Review Tools', () => {
218219
const numberOfThreads = SINGLE_LINE_MOCK_COMMENTS.filter(
219220
(c) => c.data.parent === null,
220221
).length;
221-
cy.get(buildDataCy(COMMENT_CONTAINER_CYPRESS)).should(
222+
cy.get(`[data-cy^=${COMMENT_CONTAINER_CYPRESS}]`).should(
222223
'have.length',
223224
numberOfThreads,
224225
);
225226

226227
// click the toggle visibility button
227228
cy.get(buildDataCy(TOOLBAR_VISIBILITY_BUTTON_CYPRESS)).click();
228-
cy.get(buildDataCy(COMMENT_CONTAINER_CYPRESS)).should('have.length', 0);
229+
cy.get(`[data-cy^=${COMMENT_CONTAINER_CYPRESS}]`).should('have.length', 0);
229230
cy.get(buildDataCy(TOOLBAR_VISIBILITY_BUTTON_CYPRESS)).click();
230-
cy.get(buildDataCy(COMMENT_CONTAINER_CYPRESS)).should(
231+
cy.get(`[data-cy^=${COMMENT_CONTAINER_CYPRESS}]`).should(
231232
'have.length',
232233
numberOfThreads,
233234
);
@@ -280,3 +281,42 @@ describe('Code Review Tools', () => {
280281
});
281282
});
282283
});
284+
285+
describe('Comment settings', () => {
286+
beforeEach(() => {
287+
cy.setUpApi({
288+
database: {
289+
appSettings: [
290+
CODE_REVIEW_MODE_SETTING,
291+
{
292+
...MOCK_GENERAL_SETTINGS,
293+
data: {
294+
...DEFAULT_GENERAL_SETTINGS,
295+
[GeneralSettingsKeys.MaxCommentLength]: 20,
296+
},
297+
},
298+
MOCK_CODE_SETTINGS,
299+
],
300+
},
301+
appContext: {
302+
context: Context.PLAYER,
303+
permission: PermissionLevel.Read,
304+
},
305+
});
306+
cy.visit('/');
307+
});
308+
309+
it('Limit length of comments to 20', () => {
310+
// add a new comment online 2
311+
cy.get(`[button-cy=${buildAddButtonDataCy(1)}`).click();
312+
313+
// entter some text in the field
314+
cy.get(buildDataCy(COMMENT_EDITOR_TEXTAREA_CYPRESS)).type(
315+
'0123456789 012456789',
316+
);
317+
cy.get(buildDataCy(COMMENT_EDITOR_TEXTAREA_HELPER_TEXT_CY)).should(
318+
'contain.text',
319+
'20',
320+
);
321+
});
322+
});

0 commit comments

Comments
 (0)