strapi-plugin-comments 2.0.0-rc.1 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +109 -67
  2. package/__mocks__/initSetup.js +53 -0
  3. package/admin/src/components/ActionButton/styles.js +10 -0
  4. package/admin/src/components/DiscussionThread/index.js +3 -7
  5. package/admin/src/components/DiscussionThreadItem/index.js +25 -70
  6. package/admin/src/components/DiscussionThreadItem/styles.js +4 -79
  7. package/admin/src/components/DiscussionThreadItemActions/index.js +82 -40
  8. package/admin/src/components/DiscussionThreadItemActions/styles.js +1 -12
  9. package/admin/src/components/DiscussionThreadItemApprovalFlowActions/index.js +2 -3
  10. package/admin/src/components/DiscussionThreadItemFooter/index.js +47 -0
  11. package/admin/src/components/DiscussionThreadItemFooter/styles.js +13 -0
  12. package/admin/src/components/DiscussionThreadItemReviewAction/index.js +131 -0
  13. package/admin/src/components/IconButton/styles.js +14 -0
  14. package/admin/src/components/ReportsReviewModal/index.js +1 -1
  15. package/admin/src/components/ReportsReviewTable/index.js +12 -6
  16. package/admin/src/components/StatusBadge/index.js +17 -0
  17. package/admin/src/components/StatusBadge/styles.js +17 -0
  18. package/admin/src/pages/Details/components/DetailsEntity/index.js +42 -24
  19. package/admin/src/pages/Details/components/DetailsFilters/index.js +8 -10
  20. package/admin/src/pages/Details/index.js +6 -15
  21. package/admin/src/pages/Discover/components/DiscoverTableRow/index.js +30 -67
  22. package/admin/src/translations/en.json +13 -15
  23. package/admin/src/utils/resolveCommentStatus.js +4 -4
  24. package/content-types/comment.js +0 -4
  25. package/package.json +8 -5
  26. package/server/controllers/client.js +11 -6
  27. package/server/controllers/utils/__tests__/functions.test.js +2 -2
  28. package/server/controllers/utils/parsers.js +6 -2
  29. package/server/graphql/mutations/createAbuseReport.js +8 -3
  30. package/server/graphql/mutations/createComment.js +8 -3
  31. package/server/graphql/mutations/removeComment.js +8 -3
  32. package/server/graphql/mutations/updateComment.js +8 -3
  33. package/server/graphql/queries/findAllFlat.js +4 -2
  34. package/server/graphql/queries/findAllInHierarchy.js +3 -3
  35. package/server/graphql/resolvers-config.js +13 -8
  36. package/server/graphql/types/comment-nested.js +1 -1
  37. package/server/graphql/types/comment.js +0 -1
  38. package/server/graphql/types/create-comment-author.js +1 -1
  39. package/server/graphql/types/identify-comment-author.js +1 -1
  40. package/server/graphql/types/index.js +0 -1
  41. package/server/services/__tests__/common.test.js +165 -0
  42. package/server/services/admin.js +10 -7
  43. package/server/services/client.js +45 -31
  44. package/server/services/common.js +71 -19
  45. package/server/services/utils/__tests__/functions.test.js +9 -73
  46. package/server/services/utils/functions.js +23 -34
  47. package/server/utils/__tests__/functions.test.js +17 -0
  48. package/server/utils/constants.js +1 -0
  49. package/.circleci/config.yml +0 -48
  50. package/.eslintrc +0 -35
  51. package/.github/pull_request_template.md +0 -13
  52. package/.nvmrc +0 -1
  53. package/admin/src/components/DiscussionThreadItemMeta/index.js +0 -42
  54. package/admin/src/components/DiscussionThreadItemWarnings/index.js +0 -147
  55. package/admin/src/components/DiscussionThreadItemWarnings/styles.js +0 -7
  56. package/codecov.yml +0 -4
  57. package/public/assets/logo.png +0 -0
  58. package/public/assets/preview.png +0 -0
  59. package/server/graphql/types/comment-author-user.js +0 -9
package/README.md CHANGED
@@ -1,9 +1,11 @@
1
- <div align="center">
1
+ <div align="center" width="150px">
2
2
  <img style="width: 150px; height: auto;" src="public/assets/logo.png" alt="Logo - Strapi Comments plugin" />
3
+ </div>
4
+ <div align="center">
3
5
  <h1>Strapi v4 - Comments plugin</h1>
4
- <p>Powerfull Strapi based comments moderation tool for you and your users</p>
6
+ <p>Powerful Strapi based comments moderation tool for you and your users</p>
5
7
  <a href="https://www.npmjs.org/package/strapi-plugin-comments">
6
- <img src="https://img.shields.io/npm/v/strapi-plugin-comments/latest.svg" alt="NPM Version" />
8
+ <img alt="GitHub package.json version" src="https://img.shields.io/github/package-json/v/VirtusLab-Open-Source/strapi-plugin-comments?label=npm&logo=npm">
7
9
  </a>
8
10
  <a href="https://www.npmjs.org/package/strapi-plugin-comments">
9
11
  <img src="https://img.shields.io/npm/dm/strapi-plugin-comments.svg" alt="Monthly download on NPM" />
@@ -14,6 +16,12 @@
14
16
  <a href="https://codecov.io/gh/VirtusLab-Open-Source/strapi-plugin-comments">
15
17
  <img src="https://codecov.io/gh/VirtusLab-Open-Source/strapi-plugin-comments/coverage.svg?branch=master" alt="codecov.io" />
16
18
  </a>
19
+ <a href="https://sharing.clickup.com/tl/xhcmx-83/strapiv-4-comments-roadmap">
20
+ <img src="https://img.shields.io/website?down_message=roadmap&label=product&up_message=roadmap&url=https%3A%2F%2Fsharing.clickup.com%2Ftl%2Fxhcmx-83%2Fstrapiv-4-comments-roadmap" />
21
+ </a>
22
+ <a href="https://sharing.clickup.com/b/xhcmx-63/strapiv-4-comments-board">
23
+ <img src="https://img.shields.io/website?down_message=board&label=product&up_color=blue&up_message=board&url=https%3A%2F%2Fsharing.clickup.com%2Fb%2Fxhcmx-63%2Fstrapiv-4-comments-board" />
24
+ </a>
17
25
  </div>
18
26
 
19
27
  ---
@@ -29,10 +37,10 @@ A plugin for [Strapi Headless CMS](https://github.com/strapi/strapi) that provid
29
37
 
30
38
  - **Comments Public REST + GraphQL API:** Elegant, entirely customizable and a fully extensible admin panel.
31
39
  - **Strapi &amp; generic users:** Support for built-in &amp; also generic non-Strapi users that might be the comments authors.
32
- - **Any Content Type relation:** Comments can by linked to any of your Content Types by default. Simply, you're controlling it.
40
+ - **Any Content Type relation:** Comments can be linked to any of your Content Types by default. Simply, you're controlling it.
33
41
  - **Moderation Panel:** Search & Filter through the bucket with your auditory comments. Manage them by blocking single ones or full threads. All in combined list &amp; hierarchical tree view of threads.
34
- - **Automated Bad Words filtering:** By detault end users are not allowed to post abusing comments where bad words have been used.
35
- - **Abuse Reporting & Reviewing:** Don't allow inferior language, react to reports from your community, send email notifiactions about abuse reports
42
+ - **Automated Bad Words filtering:** By default end users are not allowed to post abusing comments where bad words have been used.
43
+ - **Abuse Reporting & Reviewing:** Don't allow inferior language, react to reports from your community, send email notifications about issued reports
36
44
 
37
45
  ## ⚙️ Versions
38
46
 
@@ -60,7 +68,7 @@ or just run Strapi in the development mode with `--watch-admin` option:
60
68
  yarn develop --watch-admin
61
69
  ```
62
70
 
63
- The **Comments** plugin should appear in the navigation menu of Strapi after you run app again.
71
+ The **Comments** plugin should appear in the **Plugins** section of Strapi sidebar after you run app again.
64
72
 
65
73
  Enjoy 🎉
66
74
 
@@ -76,7 +84,7 @@ In our minimum support we're following [official Node.js releases timelines](htt
76
84
 
77
85
  **Supported Strapi versions**:
78
86
 
79
- - Strapi v4.0.5 (recently tested)
87
+ - Strapi v4.0.7 (recently tested)
80
88
  - Strapi v4.x
81
89
 
82
90
  > This plugin is designed for **Strapi v4** and is not working with v3.x. To get version for **Strapi v3** install version [v1.x](https://github.com/VirtusLab-Open-Source/strapi-plugin-comments/tree/strapi-v3).
@@ -101,6 +109,9 @@ To setup amend default plugin configuration we recommend to put following snippe
101
109
  reportReasons: {
102
110
  'MY_CUSTOM_REASON': 'MY_CUSTOM_REASON',
103
111
  },
112
+ gql: {
113
+ // ...
114
+ },
104
115
  },
105
116
  //...
106
117
  });
@@ -112,12 +123,36 @@ To setup amend default plugin configuration we recommend to put following snippe
112
123
  - `approvalFlow` - list of Content Types which are supporting approval flow. Values must be in format like `'api::<collection name>.<content type name>'`. For not included, posted comments are going to be immediately visible.
113
124
  - `entryLabel` - ordered list of property names per Content Type to generate related entity label. Keys must be in format like `'api::<collection name>.<content type name>'`. Default formatting set as `*`.
114
125
  - `reportReasons` - set of enums you would like to use for issuing abuse reports. Provided by default `'BAD_LANGUAGE'`, `'DISCRIMINATION'` and `'OTHER'`.
126
+ - `gql` - specific configuration for GraphQL. See [Additional GQL Configuration](#additional-gql-configuration)
115
127
 
116
128
  ## Additional GQL Configuration
117
- All you need to do is to install and enable `@strapi/plugin-graphql` for you instance based on the **[official Strapi v4 docs](https://docs.strapi.io/developer-docs/latest/plugins/graphql.html#configurations)**.
129
+ All you need to do is to install and enable `@strapi/plugin-graphql` for you instance based on the **[official Strapi v4 docs](https://docs.strapi.io/developer-docs/latest/plugins/graphql.html#configurations)** and decide if you would like to call it by anyone (open for world) or only by authenticated users (Strapi users).
130
+
131
+ ```json
132
+ {
133
+ // ...
134
+ gql: {
135
+ auth: true, // Default: false
136
+ },
137
+ // ...
138
+ }
139
+ ```
140
+
141
+ ### Properties
142
+ - `auth` - does GraphQL Queries should be authenticated or not? Default: `false`
143
+
144
+ ### Queries
118
145
 
119
146
  See [available GQL specification section](#public-graphql-specification).
120
147
 
148
+ > If `auth` is set to `true` you must provide relevant authentication headers to all requests like for example:
149
+ >
150
+ > ```json
151
+ > {
152
+ > "Authorization": "Bearer <your token here>"
153
+ > }
154
+ > ```
155
+
121
156
  ## 👤 RBAC
122
157
  Plugin provides granular permissions based on Strapi RBAC functionality.
123
158
 
@@ -134,7 +169,6 @@ Feature / Capability focused permissions:
134
169
 
135
170
  ## Base Comment model
136
171
 
137
- ### Generic (non Strapi User)
138
172
  ```json
139
173
  {
140
174
  "id": 1,
@@ -146,8 +180,8 @@ Feature / Capability focused permissions:
146
180
  "removed": null,
147
181
  "approvalStatus": "APPROVED", // Only in case of enabled approval flow. Default: null
148
182
  "author": {
149
- "id": "207ccfdc-94ba-45eb-979c-790f6f49c392",
150
- "name": "Joe Doe",
183
+ "id": "207ccfdc-94ba-45eb-979c-790f6f49c392", // For Strapi users id reflects to the format used by your Strapi
184
+ "name": "Joe Doe", // For Strapi users it is equal to 'username' field
151
185
  "email": "jdoe@sample.com",
152
186
  "avatar": null,
153
187
  },
@@ -156,49 +190,20 @@ Feature / Capability focused permissions:
156
190
  "related": {}, // Related content type entity
157
191
  "reports": [] // Reports issued against this comment
158
192
  }
159
- ```
160
- ### Strapi User
161
- ```json
162
- {
163
- "id": 1,
164
- "content": "My comment content",
165
- "blocked": true,
166
- "blockedThread": null,
167
- "blockReason": null,
168
- "removed": null,
169
- "approvalStatus": "REJECTED", // Only in case of enabled approval flow. Default: null
170
- "authorUser": {
171
- "id": 1,
172
- "username": "Sample User",
173
- "email": "user@sample.com",
174
- "provider": "local",
175
- "confirmed": true,
176
- "blocked": false,
177
- "role": 1,
178
- "created_at": "2020-07-10T08:38:03.157Z",
179
- "updated_at": "2020-07-10T08:38:03.170Z"
180
- },
181
- "authorId": null,
182
- "authorName": null,
183
- "authorEmail": null,
184
- "authorAvatar": null,
185
- "createdAt": "2020-07-14T20:13:01.649Z",
186
- "updatedAt": "2020-07-14T20:13:01.670Z",
187
- "related": {}, // Related content type entity
188
- "reports": [] // Reports issued against this comment
189
- }
190
-
191
193
  ```
192
194
 
193
195
  ## 🕸️ Public REST API specification
194
196
 
197
+ **Strapi Users vs. Generic authors**
198
+ > Keep in mind that if you're using auth / authz your requests to setup proper user contexts it has got higher priority in order to take author data comparing to `author` property provided as part of your payload.
199
+
195
200
  ### Get Comments
196
201
 
197
202
  *GraphQL equivalent: [Public GraphQL API -> Get Comments](#get-comments-1)*
198
203
 
199
- `GET <host>/comments/api::<collection name>.<content type name>:<entity id>`
204
+ `GET <host>/api/comments/api::<collection name>.<content type name>:<entity id>`
200
205
 
201
- Return a hierarchical tree structure of comments for specified instance of Content Type like for example `Page` with `ID: 1`
206
+ Return a hierarchical tree structure of comments for specified instance of Content Type like for example `Page` with `ID: 1`.
202
207
 
203
208
  **Example URL**: `https://localhost:1337/comments/api::page.page:1`
204
209
 
@@ -221,12 +226,14 @@ Return a hierarchical tree structure of comments for specified instance of Conte
221
226
  // ...
222
227
  ]
223
228
  ```
229
+ #### Strapi REST API properties support:
230
+ - [sorting](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest/sort-pagination.html#sorting)
224
231
 
225
232
  ### Get Comments (flat structure)
226
233
 
227
234
  *GraphQL equivalent: [Public GraphQL API -> Get Comments (flat structure)](#get-comments-flat-structure-1)*
228
235
 
229
- `GET <host>/comments/api::<collection name>.<content type name>:<entity id>/flat`
236
+ `GET <host>/api/comments/api::<collection name>.<content type name>:<entity id>/flat`
230
237
 
231
238
  Return a flat structure of comments for specified instance of Content Type like for example `Page` with `ID: 1`
232
239
 
@@ -250,11 +257,16 @@ Return a flat structure of comments for specified instance of Content Type like
250
257
  - `200` - Successful. Response with list of comments (can be empty)
251
258
  - `400` - Bad Request. Requested list for not valid / not existing Content Type
252
259
 
260
+ #### Strapi REST API properties support:
261
+ - [filtering](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest/filtering-locale-publication.html#filtering)
262
+ - [sorting](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest/sort-pagination.html#sorting)
263
+ - [pagination](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest/sort-pagination.html#pagination)
264
+
253
265
  ### Post a Comment
254
266
 
255
267
  *GraphQL equivalent: [Public GraphQL API -> Post a Comments](#post-a-comment-1)*
256
268
 
257
- `POST <host>/comments/api::<collection name>.<content type name>:<entity id>`
269
+ `POST <host>/api/comments/api::<collection name>.<content type name>:<entity id>`
258
270
 
259
271
  Posts a Comment related to specified instance of Content Type like for example `Page` with `ID: 1`
260
272
 
@@ -265,21 +277,23 @@ Posts a Comment related to specified instance of Content Type like for example `
265
277
  *Generic (non Strapi User)*
266
278
  ```json
267
279
  {
268
- "author": {
269
- "id": "<any ID like value>",
270
- "name": "Joe Doe",
271
- "email": "jdoe@sample.com",
272
- "avatar": "<any image url>"
273
- },
280
+ "author": {
281
+ "id": "<any ID like value>",
282
+ "name": "Joe Doe",
283
+ "email": "jdoe@sample.com",
284
+ "avatar": "<any image url>"
285
+ },
274
286
  "content": "My sample response",
275
287
  "threadOf": 2, // id of comment we would like to start / continue the thread (Optional)
276
288
  }
277
289
  ```
278
290
 
279
291
  *Strapi user*
292
+
293
+ > Author is taken directly from the request context
294
+
280
295
  ```json
281
296
  {
282
- "authorUser": 1, // id of a author user. Optional in case of 'enableUsers: true' in the plugin configuration
283
297
  "content": "My sample response",
284
298
  "threadOf": 2, // id of comment we would like to start / continue the thread (Optional)
285
299
  }
@@ -301,7 +315,7 @@ Posts a Comment related to specified instance of Content Type like for example `
301
315
 
302
316
  *GraphQL equivalent: [Public GraphQL API -> Update Comments](#update-comment-1)*
303
317
 
304
- `PUT <host>/comments/api::<collection name>.<content type name>:<entity id>/comment/<commentId>`
318
+ `PUT <host>/api/comments/api::<collection name>.<content type name>:<entity id>/comment/<commentId>`
305
319
 
306
320
  Updates a specified Comment content based on it `commentId` and related to specified instance of Content Type like for example `Page` with `ID: 1`
307
321
 
@@ -312,17 +326,19 @@ Updates a specified Comment content based on it `commentId` and related to speci
312
326
  *Generic (non Strapi User)*
313
327
  ```json
314
328
  {
315
- "author": {
316
- "id": "<any ID like value>"
317
- },
329
+ "author": {
330
+ "id": "<any ID like value>"
331
+ },
318
332
  "content": "My sample response"
319
333
  }
320
334
  ```
321
335
 
322
336
  *Strapi user*
337
+
338
+ > Author is taken directly from the request context
339
+
323
340
  ```json
324
341
  {
325
- "authorUser": 1, // id of a author user. Optional in case of 'enableUsers: true' in the plugin configuration
326
342
  "content": "My sample response"
327
343
  }
328
344
  ```
@@ -344,7 +360,7 @@ Updates a specified Comment content based on it `commentId` and related to speci
344
360
 
345
361
  *GraphQL equivalent: [Public GraphQL API -> Delete Comment](#delete-comment-1)*
346
362
 
347
- `DELETE <host>/comments/api::<collection name>.<content type name>:<entity id>/<commentId>?authorId=<authorId>`
363
+ `DELETE <host>/api/comments/api::<collection name>.<content type name>:<entity id>/<commentId>?authorId=<authorId>`
348
364
 
349
365
  Deletes a specified Comment based on it `commentId` and related to specified instance of Content Type like for example `Page` with `ID: 1`.
350
366
 
@@ -367,7 +383,7 @@ Deletes a specified Comment based on it `commentId` and related to specified ins
367
383
 
368
384
  *GraphQL equivalent: [Public GraphQL API -> Issue Abuse Report against specified Comment](#issue-abuse-report-against-specified-comment-1)*
369
385
 
370
- `POST <host>/comments/api::<collection name>.<content type name>:<entity id>/comment/<commentId>/report-abuse`
386
+ `POST <host>/api/comments/api::<collection name>.<content type name>:<entity id>/comment/<commentId>/report-abuse`
371
387
 
372
388
  Reports abuse in specified Comment content based on it `commentId` and related to specified instance of Content Type like for example `Page` with `ID: 1` and requests moderator attention.
373
389
 
@@ -398,7 +414,11 @@ Reports abuse in specified Comment content based on it `commentId` and related t
398
414
 
399
415
  ## 🕸️ Public GraphQL specification
400
416
 
401
- > *To test all queries and understand the schemas use GraphQL Playground exposed by `@strapi/plugin-graphql` on `http://localhost:1337/graphql`*
417
+ **Strapi Users vs. Generic authors**
418
+ > Keep in mind that if you're using auth / authz your requests to setup proper user contexts it has got higher priority in order to take author data comparing to `author` property provided as part of your payload.
419
+
420
+ **Testing**
421
+ > To test all queries and understand the schemas use GraphQL Playground exposed by `@strapi/plugin-graphql` on `http://localhost:1337/graphql`
402
422
 
403
423
  ### Get Comments
404
424
 
@@ -447,6 +467,9 @@ query {
447
467
  }
448
468
  ```
449
469
 
470
+ #### Strapi GraphQL API properties support:
471
+ - [sorting](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/graphql-api.html#sorting)
472
+
450
473
  ### Get Comments (flat structure)
451
474
 
452
475
  *REST API equivalent: [Public REST API -> Get Comments (flat structure)](#get-comments-flat-structure)*
@@ -503,6 +526,11 @@ query {
503
526
  }
504
527
  ```
505
528
 
529
+ #### Strapi GraphQL API properties support:
530
+ - [filtering](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/graphql-api.html#filters)
531
+ - [sorting](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/graphql-api.html#sorting)
532
+ - [pagination](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/graphql-api.html#pagination)
533
+
506
534
  ### Post a Comment
507
535
 
508
536
  *REST API equivalent: [Public REST API -> Post a Comment](#post-a-comment)*
@@ -516,7 +544,7 @@ mutation createComment {
516
544
  relation: "api::page.page:1"
517
545
  content: "Hello World!"
518
546
  threadOf: 3
519
- author: { id: "12345678", name: "John Wick", email: "test@test.pl" }
547
+ author: { id: "12345678", name: "John Wick", email: "test@test.pl" } # Optional if using auth / authz requests
520
548
  }
521
549
  ) {
522
550
  id
@@ -565,7 +593,7 @@ mutation updateComment {
565
593
  id: 34
566
594
  relation: "api::page.page:1"
567
595
  content: "I've changed it!"
568
- author: { id: "12345678" }
596
+ author: { id: "12345678" } # Optional if using auth / authz requests
569
597
  }
570
598
  ) {
571
599
  id
@@ -614,7 +642,11 @@ mutation updateComment {
614
642
  ```graphql
615
643
  mutation removeComment {
616
644
  removeComment(
617
- input: { id: 33, relation: "api::page.page:1", author: { id: "12345678" } }
645
+ input: {
646
+ id: 33,
647
+ relation: "api::page.page:1",
648
+ author: { id: "12345678" } # Optional if using auth / authz requests
649
+ }
618
650
  ) {
619
651
  id
620
652
  removed
@@ -694,15 +726,25 @@ Live example of plugin usage can be found in the [VirtusLab Strapi Examples](htt
694
726
 
695
727
  ## 🤝 Contributing
696
728
 
729
+ <div>
730
+ <a href="https://sharing.clickup.com/tl/xhcmx-83/strapiv-4-comments-roadmap">
731
+ <img src="https://img.shields.io/website?down_message=roadmap&label=product&up_message=roadmap&url=https%3A%2F%2Fsharing.clickup.com%2Ftl%2Fxhcmx-83%2Fstrapiv-4-comments-roadmap" />
732
+ </a>
733
+ <a href="https://sharing.clickup.com/b/xhcmx-63/strapiv-4-comments-board">
734
+ <img src="https://img.shields.io/website?down_message=board&label=product&up_color=blue&up_message=board&url=https%3A%2F%2Fsharing.clickup.com%2Fb%2Fxhcmx-63%2Fstrapiv-4-comments-board" />
735
+ </a>
736
+ </div>
737
+
697
738
  Feel free to fork and make a Pull Request to this plugin project. All the input is warmly welcome!
698
739
 
699
740
  ## 👨‍💻 Community support
700
741
 
701
742
  For general help using Strapi, please refer to [the official Strapi documentation](https://strapi.io/documentation/). For additional help, you can use one of these channels to ask a question:
702
743
 
703
- - [Discord](https://discord.strapi.io/) We're present on official Strapi Discord workspace. Look for @cyp3r and DM.
744
+ - [Discord](https://discord.strapi.io/) We're present on official Strapi Discord workspace. Find us by `[VirtusLab]` prefix and DM.
704
745
  - [Slack - VirtusLab Open Source](https://virtuslab-oss.slack.com) We're present on a public channel #strapi-molecules
705
746
  - [GitHub](https://github.com/VirtusLab-Open-Source/strapi-plugin-comments/issues) (Bug reports, Contributions, Questions and Discussions)
747
+ - [E-mail](mailto:strapi@virtuslab.com) - we will respond back as soon as possible
706
748
 
707
749
  ## 📝 License
708
750
 
@@ -0,0 +1,53 @@
1
+ const { get, set } = require('lodash');
2
+
3
+ module.exports = (config = {}) => {
4
+ const mock = {
5
+ getRef: function() {
6
+ return this;
7
+ },
8
+ plugin: function(name) {
9
+ return this.plugins[name];
10
+ },
11
+ plugins: {
12
+ comments: {
13
+ service: function(name) {
14
+ return this.services[name]({ strapi: mock.getRef() });
15
+ },
16
+ package: require('../package.json'),
17
+ services: {
18
+ common: require('../server/services/common'),
19
+ client: require('../server/services/client'),
20
+ admin: require('../server/services/admin'),
21
+ },
22
+ contentTypes: {
23
+ comment: {
24
+ ...require('../content-types/comment'),
25
+ uid: 'plugins::comments.comment',
26
+ },
27
+ 'comment-report': {
28
+ ...require('../content-types/report'),
29
+ uid: 'plugins::comments.comment-report'
30
+ },
31
+ }
32
+ }
33
+ },
34
+ config: {
35
+ get: function(prop = '') {
36
+ return get(this.plugins, prop.replace('plugin.', ''));
37
+ },
38
+ set: function(prop = '', value) {
39
+ return set(this.plugins, prop.replace('plugin.', ''), value);
40
+ },
41
+ plugins: {
42
+ comments: {
43
+ approvalFlow: ['api::blog-post.blog-post'],
44
+ entryLabel: {
45
+ 'api::blog-post.blog-post': ['alternative_subject'],
46
+ },
47
+ ...config
48
+ }
49
+ }
50
+ }
51
+ };
52
+ return mock;
53
+ };
@@ -0,0 +1,10 @@
1
+
2
+ import styled from 'styled-components';
3
+ import { Button } from '@strapi/design-system/Button';
4
+
5
+ export const ActionButton = styled(Button)`
6
+ padding: 7px 16px;
7
+ margin-left: ${({ isSingle }) => isSingle ? '0' : '.5rem'};
8
+
9
+ white-space: nowrap;
10
+ `;
@@ -8,7 +8,6 @@ import React from 'react';
8
8
  import PropTypes from 'prop-types';
9
9
  import { isNil } from 'lodash';
10
10
  import { Box } from '@strapi/design-system/Box';
11
- import { Divider } from '@strapi/design-system/Divider';
12
11
  import { Flex } from '@strapi/design-system/Flex';
13
12
  import { Link } from '@strapi/design-system/Link';
14
13
  import { Typography } from '@strapi/design-system/Typography';
@@ -22,22 +21,19 @@ const DiscussionThread = ({ level = [], selected = {}, allowedActions, isReloadi
22
21
  const rootThread = selected?.threadOf;
23
22
  return (<LoadingIndicatorContainer as={Box} padding={4}>
24
23
  { isReloading && <LoadingIndicatorOverlay />}
25
- <Flex as={Box} direction="row" justifyContent="space-between">
26
- <Typography variant="sigma" textColor="neutral600" id="entity-details">
24
+ <Flex as={Box} direction="row" justifyContent="space-between" marginBottom={2}>
25
+ <Typography variant="delta" textColor="neutral800" id="discussion-thread">
27
26
  { getMessage('page.details.panel.discussion', 'Discussion') }
28
27
  </Typography>
29
28
  { rootThread && (<Link to={getUrl(`discover/${rootThread.id}`)} startIcon={<ArrowUp />}>
30
29
  { getMessage('page.details.panel.discussion.nav.back') }
31
30
  </Link>) }
32
31
  </Flex>
33
- <Box paddingTop={2} paddingBottom={6}>
34
- <Divider />
35
- </Box>
36
32
  <Flex as="ul" direction="column" alignItems="flex-start">
37
33
  { rootThread && (<DiscussionThreadItem {...rootThread} allowedActions={allowedActions} isThreadAuthor root pinned />) }
38
34
  { level.map(item => {
39
35
  const isSelected = selected.id === item.id;
40
- const isThreadAuthor = !isNil(selected?.threadOf?.authorId) && (selected?.threadOf?.authorId === item.authorId);
36
+ const isThreadAuthor = !isNil(selected?.threadOf?.author?.id) && (selected?.threadOf?.author?.id === item?.author?.id);
41
37
  return (<DiscussionThreadItem
42
38
  key={`comment-${item.id}`}
43
39
  {...item}
@@ -1,92 +1,47 @@
1
1
  /**
2
2
  *
3
- * Entity Details
3
+ * Discussion thread - Item
4
4
  *
5
5
  */
6
6
 
7
7
  import React from 'react';
8
8
  import PropTypes from 'prop-types';
9
- import { Avatar, Initials } from '@strapi/design-system/Avatar';
10
9
  import { Box } from '@strapi/design-system/Box';
11
- import { Divider } from '@strapi/design-system/Divider';
12
10
  import { Flex } from '@strapi/design-system/Flex';
13
- import { Link } from '@strapi/design-system/Link';
14
11
  import { Typography } from '@strapi/design-system/Typography';
15
- import { ArrowRight } from '@strapi/icons';
16
- import DiscussionThreadItemMeta from '../DiscussionThreadItemMeta';
17
- import { AvatarWrapper, DiscussionThreadItemBox, DiscussionThreadItemBoxContent, DiscussionThreadItemContent, DiscussionThreadItemLeft, DiscussionThreadItemLinkBox, DiscussionThreadItemRight, DiscussionThreadItemRoot } from './styles';
12
+ import DiscussionThreadItemFooter from '../DiscussionThreadItemFooter';
18
13
  import DiscussionThreadItemActions from '../DiscussionThreadItemActions';
19
- import { getMessage, getUrl, renderInitials } from '../../utils';
20
- import DiscussionThreadItemWarnings from '../DiscussionThreadItemWarnings';
14
+ import { DiscussionThreadItemContainer, DiscussionThreadFullsize, DiscussionThreadItemContent } from './styles';
21
15
 
22
16
  const DiscussionThreadItem = (props) => {
23
17
  const {
18
+ as = "li",
24
19
  isSelected,
25
- isThreadAuthor,
26
20
  content,
27
21
  root,
28
22
  preview,
29
- pinned,
30
- blocked,
31
- removed,
32
- blockedThread,
33
- gotThread,
34
- threadFirstItemId,
35
- authorUser,
36
- author } = props;
37
-
38
- let background = 'neutral100';
39
- let borderColor = 'neutral200';
40
- let dividerColor = 'neutral200';
41
- let StyledComponent = DiscussionThreadItemRight;
42
-
43
- if(isThreadAuthor || root){
44
- StyledComponent = DiscussionThreadItemLeft;
45
- borderColor = 'neutral100';
46
- dividerColor = 'neutral100';
47
- background = null;
48
- }
49
-
50
- if (isSelected) {
51
- background = 'secondary100'
52
- borderColor = 'secondary500';
53
- dividerColor = 'secondary200';
54
- }
55
-
56
- if (root) {
57
- StyledComponent = DiscussionThreadItemRoot;
58
- }
59
-
60
- const avatar = author?.avatar || authorUser?.avatar;
61
- const name = author?.name || `${authorUser?.firstName} ${authorUser?.lastName}`;
62
- const isBlocked = blocked || blockedThread;
23
+ pinned } = props;
63
24
 
64
- return (<StyledComponent as="li">
65
- <DiscussionThreadItemContent as={Flex} direction="row">
66
- <AvatarWrapper>
67
- { avatar ? <Avatar src={avatar} alt={name} /> : <Initials>{ renderInitials(name) }</Initials> }
68
- </AvatarWrapper>
69
- <DiscussionThreadItemBox hasRadius shadow="filterShadow" borderColor={borderColor} background={background} padding={2}>
70
- <Flex as={Box} paddingBottom={2} direction="column">
71
- <DiscussionThreadItemBoxContent as={Flex} direction="row">
72
- <Box as={Flex} grow={1} alignItems="center">
73
- <Typography variant="omega">{ content }</Typography>
74
- </Box>
75
- { !preview && (<DiscussionThreadItemActions { ...props } root={root || pinned} />) }
76
- </DiscussionThreadItemBoxContent>
77
- { !(preview || isBlocked || removed) && (<DiscussionThreadItemWarnings { ...props } gotThread={gotThread || root} />) }
78
- </Flex>
79
- <Divider background={dividerColor} />
80
- <DiscussionThreadItemMeta { ...props } />
81
- </DiscussionThreadItemBox>
82
- </DiscussionThreadItemContent>
83
-
84
- { (gotThread && !(removed || preview || pinned)) && (<DiscussionThreadItemLinkBox direction="column" alignItems="flex-end">
85
- <Link to={getUrl(`discover/${threadFirstItemId}`)} endIcon={<ArrowRight />}>
86
- { getMessage('page.details.panel.discussion.nav.drilldown') }
87
- </Link>
88
- </DiscussionThreadItemLinkBox>) }
89
- </StyledComponent>);
25
+ return (<DiscussionThreadFullsize as={as} marginBottom={preview ? 4 : 0}>
26
+ <DiscussionThreadItemContainer
27
+ as={Flex}
28
+ direction="column"
29
+ alignItems="flex-start"
30
+ hasRadius
31
+ background={isSelected ? 'neutral100' : null}
32
+ paddingLeft={2} paddingRight={2} paddingTop={4} paddingBottom={4}>
33
+ <DiscussionThreadItemContent
34
+ as={Flex}
35
+ paddingBottom={2}
36
+ direction="row">
37
+ <Box as={Flex} grow={1} alignItems="center" marginTop="6px">
38
+ <Typography variant="omega" textColor="neutral800">{ content }</Typography>
39
+ </Box>
40
+ { !preview && (<DiscussionThreadItemActions { ...props } root={root || pinned} preview={preview} />) }
41
+ </DiscussionThreadItemContent>
42
+ <DiscussionThreadItemFooter { ...props } />
43
+ </DiscussionThreadItemContainer>
44
+ </DiscussionThreadFullsize>);
90
45
  };
91
46
 
92
47
  DiscussionThreadItem.propTypes = {