diff --git a/Dockerfile b/Dockerfile
index 98400857..bf14c398 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -46,9 +46,9 @@ RUN pip install --no-cache-dir -U pip \
&& rm -rf /deps
COPY --chown=doccano:doccano . /doccano
-WORKDIR /doccano
+WORKDIR /doccano/app
COPY --from=frontend-builder /frontend/dist /doccano/app/client/dist
-RUN python app/manage.py collectstatic --noinput
+RUN python manage.py collectstatic --noinput
VOLUME /data
ENV DATABASE_URL="sqlite:////data/doccano.db"
@@ -61,7 +61,6 @@ ENV GOOGLE_TRACKING_ID=""
ENV AZURE_APPINSIGHTS_IKEY=""
USER doccano
-WORKDIR /doccano
EXPOSE ${PORT}
CMD ["/doccano/tools/run.sh"]
diff --git a/app/api/migrations/0004_merge_20210114_1117.py b/app/api/migrations/0004_merge_20210114_1117.py
new file mode 100644
index 00000000..881e8b55
--- /dev/null
+++ b/app/api/migrations/0004_merge_20210114_1117.py
@@ -0,0 +1,14 @@
+# Generated by Django 3.1.5 on 2021-01-14 11:17
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('api', '0002_comment'),
+ ('api', '0003_merge_20200612_0205'),
+ ]
+
+ operations = [
+ ]
diff --git a/app/api/serializers.py b/app/api/serializers.py
index 0acb47e6..78444cc1 100644
--- a/app/api/serializers.py
+++ b/app/api/serializers.py
@@ -7,7 +7,7 @@ from rest_framework.exceptions import ValidationError
from .models import Label, Project, Document, RoleMapping, Role, Comment
-from .models import TextClassificationProject, SequenceLabelingProject, Seq2seqProject
+from .models import TextClassificationProject, SequenceLabelingProject, Seq2seqProject, Speech2textProject
from .models import DocumentAnnotation, SequenceAnnotation, Seq2seqAnnotation, Speech2textAnnotation
diff --git a/frontend/components/containers/annotation/CommentButton.vue b/frontend/components/containers/annotation/CommentButton.vue
new file mode 100644
index 00000000..074c3744
--- /dev/null
+++ b/frontend/components/containers/annotation/CommentButton.vue
@@ -0,0 +1,158 @@
+
+
+
+
+
+
+ mdi-chat
+
+
+
+ {{ $t('annotation.commentTooltip') }}
+
+
+
+
+
+
+
+ mdi-plus
+
+
+
+
+
+
+ mdi-delete
+
+
+
+
+ {{ props.item.text }}
+
+
+ Update Comment
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/i18n/en/projects/annotation.js b/frontend/i18n/en/projects/annotation.js
index 7e893b5d..de88642b 100644
--- a/frontend/i18n/en/projects/annotation.js
+++ b/frontend/i18n/en/projects/annotation.js
@@ -7,6 +7,8 @@ export default {
filterOption3: 'Undone',
guidelineTooltip: 'Show Guideline',
guidelinePopupTitle: 'Annotation Guideline',
+ commentTooltip: 'Click to comment on document',
+ commentPopupTitle: 'Comment',
metadataDefaultMessage: 'No data available',
key: 'Key',
value: 'Value',
diff --git a/frontend/layouts/annotation.vue b/frontend/layouts/annotation.vue
index a49f76d8..b964b4ec 100644
--- a/frontend/layouts/annotation.vue
+++ b/frontend/layouts/annotation.vue
@@ -39,6 +39,7 @@
v-model="filterOption"
/>
+
@@ -79,6 +80,7 @@ import GuidelineButton from '@/components/containers/annotation/GuidelineButton'
import MetadataBox from '@/components/organisms/annotation/MetadataBox'
import FilterButton from '@/components/containers/annotation/FilterButton'
import ApproveButton from '@/components/containers/annotation/ApproveButton'
+import CommentButton from '@/components/containers/annotation/CommentButton'
import Pagination from '~/components/containers/annotation/Pagination'
import TheHeader from '~/components/organisms/layout/TheHeader'
import TheSideBar from '~/components/organisms/layout/TheSideBar'
@@ -95,7 +97,8 @@ export default {
FilterButton,
ApproveButton,
MetadataBox,
- ClearAnnotationsButton
+ ClearAnnotationsButton,
+ CommentButton
},
fetch() {
diff --git a/frontend/services/comment.service.js b/frontend/services/comment.service.js
new file mode 100644
index 00000000..369e8f52
--- /dev/null
+++ b/frontend/services/comment.service.js
@@ -0,0 +1,26 @@
+import ApiService from '@/services/api.service'
+
+class CommentService {
+ constructor() {
+ this.request = ApiService
+ }
+
+ getCommentList({ projectId, docId }) {
+ return this.request.get(`/projects/${projectId}/docs/${docId}/comments`)
+ }
+
+ addComment(projectId, docId, payload) {
+ console.log(payload)
+ return this.request.post(`/projects/${projectId}/docs/${docId}/comments`, payload)
+ }
+
+ deleteComment(projectId, docId, commentId) {
+ return this.request.delete(`/projects/${projectId}/docs/${docId}/comments/${commentId}`)
+ }
+
+ updateComment(projectId, docId, commentId, payload) {
+ return this.request.patch(`/projects/${projectId}/docs/${docId}/comments/${commentId}`, payload)
+ }
+}
+
+export default new CommentService()
diff --git a/frontend/store/documents.js b/frontend/store/documents.js
index 287e7d56..79220f52 100644
--- a/frontend/store/documents.js
+++ b/frontend/store/documents.js
@@ -1,3 +1,4 @@
+import CommentService from '@/services/comment.service'
import DocumentService from '@/services/document.service'
import AnnotationService from '@/services/annotation.service'
@@ -73,6 +74,16 @@ export const mutations = {
const item = state.items[state.current].annotations.find(item => item.id === payload.id)
Object.assign(item, payload)
},
+ addComment(state, payload) {
+ state.items[state.current].comments.push(payload)
+ },
+ updateComment(state, payload) {
+ const item = state.items[state.current].comments.find(item => item.id === payload.id)
+ Object.assign(item, payload)
+ },
+ deleteComment(state, commentId) {
+ state.items[state.current].comments = state.items[state.current].comments.filter(item => item.id !== commentId)
+ },
updateSearchOptions(state, payload) {
state.searchOptions = Object.assign(state.searchOptions, payload)
},
@@ -222,5 +233,35 @@ export const actions = {
.catch((error) => {
alert(error)
})
+ },
+ addComment({ commit, state }, payload) {
+ const documentId = state.items[state.current].id
+ CommentService.addComment(payload.projectId, documentId, payload)
+ .then((response) => {
+ commit('addComment', response.data)
+ })
+ .catch((error) => {
+ alert(error)
+ })
+ },
+ updateComment({ commit, state }, payload) {
+ const documentId = state.items[state.current].id
+ CommentService.updateComment(payload.projectId, documentId, payload.commentId, payload)
+ .then((response) => {
+ commit('updateComment', response.data)
+ })
+ .catch((error) => {
+ alert(error)
+ })
+ },
+ deleteComment({ commit, state }, payload) {
+ const documentId = state.items[state.current].id
+ CommentService.deleteComment(payload.projectId, documentId, payload.commentId)
+ .then((response) => {
+ commit('deleteComment', payload.commentId)
+ })
+ .catch((error) => {
+ alert(error)
+ })
}
}