Assign and view translator
This commit is contained in:
16
package-lock.json
generated
16
package-lock.json
generated
@@ -1426,7 +1426,7 @@
|
||||
},
|
||||
"node_modules/mantra-db-models": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "git+https://code.sigidli.com/mantra/mantra-db-models.git#40423458f5e549406ebf5433073d135497d7ec79",
|
||||
"resolved": "git+https://code.sigidli.com/mantra/mantra-db-models.git#c26cf2b6a0d789b4441d4c76443ac419ae787b7c",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"bcrypt": "^5.0.1",
|
||||
@@ -1518,9 +1518,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/minipass": {
|
||||
"version": "3.1.6",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz",
|
||||
"integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==",
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.3.tgz",
|
||||
"integrity": "sha512-N0BOsdFAlNRfmwMhjAsLVWOk7Ljmeb39iqFlsV1At+jqRhSUP9yeof8FyJu4imaJiSUp8vQebWD/guZwGQC8iA==",
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
@@ -4011,7 +4011,7 @@
|
||||
}
|
||||
},
|
||||
"mantra-db-models": {
|
||||
"version": "git+https://code.sigidli.com/mantra/mantra-db-models.git#40423458f5e549406ebf5433073d135497d7ec79",
|
||||
"version": "git+https://code.sigidli.com/mantra/mantra-db-models.git#c26cf2b6a0d789b4441d4c76443ac419ae787b7c",
|
||||
"from": "mantra-db-models@git+https://code.sigidli.com/mantra/mantra-db-models.git",
|
||||
"requires": {
|
||||
"bcrypt": "^5.0.1",
|
||||
@@ -4079,9 +4079,9 @@
|
||||
}
|
||||
},
|
||||
"minipass": {
|
||||
"version": "3.1.6",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz",
|
||||
"integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==",
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.3.tgz",
|
||||
"integrity": "sha512-N0BOsdFAlNRfmwMhjAsLVWOk7Ljmeb39iqFlsV1At+jqRhSUP9yeof8FyJu4imaJiSUp8vQebWD/guZwGQC8iA==",
|
||||
"requires": {
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
|
||||
@@ -1164,6 +1164,21 @@ module.exports = function (options) {
|
||||
},
|
||||
{
|
||||
association: db.TranslationChapter.TranslationChapterTranslators,
|
||||
include: [
|
||||
{
|
||||
association: db.TranslationChapterTranslator.Translator,
|
||||
include: [
|
||||
{
|
||||
association: db.Entity.EntityEmail,
|
||||
include: [
|
||||
{
|
||||
association: db.EntityEmail.Email
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
association: db.TranslationChapter.TranslationChapterProofReaders,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const express = require('express')
|
||||
const { Op } = require("sequelize")
|
||||
const idGenerator = require('mantra-db-models/src/lib/id-generator')
|
||||
|
||||
module.exports = function (options) {
|
||||
const db = options.db;
|
||||
@@ -111,6 +112,21 @@ module.exports = function (options) {
|
||||
},
|
||||
{
|
||||
association: db.TranslationChapter.TranslationChapterTranslators,
|
||||
include: [
|
||||
{
|
||||
association: db.TranslationChapterTranslator.Translator,
|
||||
include: [
|
||||
{
|
||||
association: db.Entity.EntityEmail,
|
||||
include: [
|
||||
{
|
||||
association: db.EntityEmail.Email
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
association: db.TranslationChapter.TranslationChapterProofReaders,
|
||||
@@ -849,5 +865,208 @@ module.exports = function (options) {
|
||||
next(error)
|
||||
})
|
||||
})
|
||||
|
||||
router.route('/:id/chapter/:chapterId/translator')
|
||||
.get(function(request, response, next) {
|
||||
db.TranslationChapter.findByPk(request.params.chapterId, {
|
||||
include: [
|
||||
{
|
||||
association: db.TranslationChapter.Chapter,
|
||||
},
|
||||
{
|
||||
association: db.TranslationChapter.TranslationChapterTranslators,
|
||||
},
|
||||
{
|
||||
association: db.TranslationChapter.TranslationChapterProofReaders,
|
||||
},
|
||||
{
|
||||
association: db.TranslationChapter.TranslationChunks,
|
||||
include: [
|
||||
{
|
||||
association: db.TranslationChunk.Translation
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
association: db.TranslationChapter.TranslationArtifactVersion,
|
||||
include: [
|
||||
{
|
||||
association: db.TranslationArtifactVersion.ArtifactVersion,
|
||||
include: [
|
||||
{
|
||||
association: db.ArtifactVersion.Artifact,
|
||||
include: [
|
||||
{
|
||||
association: db.Artifact.Dialect
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
association: db.TranslationArtifactVersion.Dialect
|
||||
},
|
||||
{
|
||||
association: db.TranslationArtifactVersion.BackTranslationFrom
|
||||
},
|
||||
{
|
||||
association: db.TranslationArtifactVersion.TranslationArtifactVersionEditor,
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}).then(translationChapter => {
|
||||
if (translationChapter) {
|
||||
response.display("translate-chapter-translator-form", {
|
||||
user: request.user,
|
||||
pageTitle: `Translate Chapter ${translationChapter.name}`,
|
||||
translationChapter: translationChapter
|
||||
})
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
}).catch(error => {
|
||||
next(error)
|
||||
})
|
||||
})
|
||||
.post(function(request, response, next) {
|
||||
db.TranslationChapter.findByPk(request.params.chapterId, {
|
||||
include: [
|
||||
{
|
||||
association: db.TranslationChapter.Chapter,
|
||||
},
|
||||
{
|
||||
association: db.TranslationChapter.TranslationChapterTranslators,
|
||||
},
|
||||
{
|
||||
association: db.TranslationChapter.TranslationChapterProofReaders,
|
||||
},
|
||||
{
|
||||
association: db.TranslationChapter.TranslationChunks,
|
||||
include: [
|
||||
{
|
||||
association: db.TranslationChunk.Translation
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
association: db.TranslationChapter.TranslationArtifactVersion,
|
||||
include: [
|
||||
{
|
||||
association: db.TranslationArtifactVersion.ArtifactVersion,
|
||||
include: [
|
||||
{
|
||||
association: db.ArtifactVersion.Artifact,
|
||||
include: [
|
||||
{
|
||||
association: db.Artifact.Dialect
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
association: db.TranslationArtifactVersion.Dialect
|
||||
},
|
||||
{
|
||||
association: db.TranslationArtifactVersion.BackTranslationFrom
|
||||
},
|
||||
{
|
||||
association: db.TranslationArtifactVersion.TranslationArtifactVersionEditor,
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}).then(async (translationChapter) => {
|
||||
if (translationChapter) {
|
||||
// TODO: Check if translationChapter has a TranslationChapterTranslator with this email...
|
||||
// TODO: FindOrCreate Email
|
||||
const [email, created] = await db.Email.findOrCreate({
|
||||
where: {
|
||||
address: request.body.translator
|
||||
},
|
||||
include: [
|
||||
{
|
||||
association: db.Email.EntityEmails,
|
||||
required: false,
|
||||
where: {
|
||||
creatorId: request.user.id
|
||||
}
|
||||
},
|
||||
{
|
||||
association: db.Email.UserEmail,
|
||||
include: [
|
||||
{
|
||||
association: db.UserEmail.User,
|
||||
include: [
|
||||
{
|
||||
association: db.User.IndividualEntityUser,
|
||||
include: [
|
||||
{
|
||||
association: db.IndividualEntityUser.EntityUser
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
defaults: {
|
||||
address: request.body.translator
|
||||
}
|
||||
})
|
||||
console.log("Email: ", email.toJSON())
|
||||
if (email.userEmail) {
|
||||
// if email has user associated with it tie that users individual entity to a new TranslationChapterTranslator object
|
||||
await db.TranslationChapterTranslator.create({
|
||||
translationChapterId: translationChapter.id,
|
||||
creatorId: request.user.id,
|
||||
translatorId: email.userEmail.user.individualEntityUser.entityUser.entityId
|
||||
})
|
||||
} else if (email.entityEmails?.length > 0) {
|
||||
// TODO: If email has an EntityEmail (which has this user as a creator) tie that entityEmail to a new TranslationChapterTranslator
|
||||
await db.TranslationChapterTranslator.create({
|
||||
translationChapterId: translationChapter.id,
|
||||
creatorId: request.user.id,
|
||||
translatorId: email.entityEmails[0].entityId
|
||||
})
|
||||
} else {
|
||||
// if email doesn't have a user/entityEmail associated with it (newly created) create an EntityEmail and tie it to a new TranslationChapterTranslator object
|
||||
await db.TranslationChapterTranslator.create({
|
||||
translationChapterId: translationChapter.id,
|
||||
creatorId: request.user.id,
|
||||
translator: {
|
||||
name: idGenerator.generateRandomAlphanumeric(),
|
||||
type: "individual",
|
||||
entityEmail: {
|
||||
creatorId: request.user.id,
|
||||
emailAddress: email.address,
|
||||
type: 'translator'
|
||||
}
|
||||
}
|
||||
}, {
|
||||
include: [
|
||||
{
|
||||
association: db.TranslationChapterTranslator.Translator,
|
||||
include: [
|
||||
{
|
||||
association: db.Entity.EntityEmail
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
response.redirect(`/translate/${translationChapter.translationArtifactVersion.id}/chapter/${translationChapter.id}`)
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
}).catch(error => {
|
||||
next(error)
|
||||
})
|
||||
})
|
||||
|
||||
return router;
|
||||
};
|
||||
@@ -59,4 +59,18 @@ html {
|
||||
.tracker-dropdown {
|
||||
margin-left: 0;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
.initial-icon {
|
||||
display:inline-block;
|
||||
font-size:1em;
|
||||
width:2.5em;
|
||||
height:2.5em;
|
||||
line-height:2.5em;
|
||||
text-align:center;
|
||||
border-radius:50%;
|
||||
background:plum;
|
||||
vertical-align:middle;
|
||||
margin-right:1em;
|
||||
color:white;
|
||||
}
|
||||
4
server/views/js/init-translator-autocomplete.js
Normal file
4
server/views/js/init-translator-autocomplete.js
Normal file
@@ -0,0 +1,4 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var elems = document.querySelectorAll('#translator-input');
|
||||
var instances = M.Autocomplete.init(elems, {});
|
||||
});
|
||||
4
server/views/js/init-translator-dropdown.js
Normal file
4
server/views/js/init-translator-dropdown.js
Normal file
@@ -0,0 +1,4 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var elems = document.querySelectorAll('#translator-dropdown');
|
||||
var instances = M.Dropdown.init(elems, {});
|
||||
});
|
||||
@@ -45,18 +45,43 @@ block content
|
||||
a.dropdown-trigger editor ▼
|
||||
tbody
|
||||
each translationChapter in translationChapters.sort((a, b) => a.index - b.index)
|
||||
tr(onclick=`window.location='/translate/${translationChapter.translationArtifactVersion.id}/chapter/${translationChapter.id}'`)
|
||||
-
|
||||
const onclickResponse = `window.location='/translate/${translationChapter.translationArtifactVersion.id}/chapter/${translationChapter.id}'`
|
||||
tr
|
||||
//- TODO: link to the translationChapter...
|
||||
td
|
||||
p
|
||||
label
|
||||
input(type="checkbox")
|
||||
//- TODO: Make this a issueId...
|
||||
input(name="selectedTranslationChapters", type="checkbox", value=translationChapter.id)
|
||||
span
|
||||
td.truncate(title=translationChapter.chapter.name)= translationChapter.chapter.name
|
||||
td
|
||||
td(onclick=onclickResponse)
|
||||
span.truncate(title=translationChapter.chapter.name)= translationChapter.chapter.name
|
||||
td(onclick=onclickResponse)
|
||||
a(href=`/projects/${project.id}/tracker?dialectId=${translationChapter.translationArtifactVersion.dialect.id}`)= translationChapter.translationArtifactVersion.dialect.name
|
||||
td #{translationChapter.translationArtifactVersion.artifactVersion.artifact.name} - #{translationChapter.translationArtifactVersion.artifactVersion.tag}
|
||||
td= translationChapter.index
|
||||
td
|
||||
td
|
||||
td
|
||||
-
|
||||
const artifactName = `${translationChapter.translationArtifactVersion.artifactVersion.artifact.name} - ${translationChapter.translationArtifactVersion.artifactVersion.tag}`
|
||||
td(onclick=onclickResponse)
|
||||
span.truncate(title=artifactName)= artifactName
|
||||
td(onclick=onclickResponse)= translationChapter.index
|
||||
td(onclick=onclickResponse)
|
||||
each translationChapterTranslator in translationChapter.translationChapterTranslators
|
||||
a(href=`/projects/${project.id}/tracker?translatorId=${translationChapterTranslator.translatorId}`)
|
||||
-
|
||||
const translatorDisplayName = translationChapterTranslator.translator.entityEmail == null ? translationChapterTranslator.translator.name : translationChapterTranslator.translator.entityEmail.email.address
|
||||
const stringToColour = function(str) {
|
||||
var hash = 0;
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
||||
}
|
||||
var colour = '#';
|
||||
for (var i = 0; i < 3; i++) {
|
||||
var value = (hash >> (i * 8)) & 0xFF;
|
||||
colour += ('00' + value.toString(16)).substr(-2);
|
||||
}
|
||||
return colour;
|
||||
}
|
||||
|
||||
span.initial-icon(style=`background: ${stringToColour(translationChapterTranslator.translatorId)};`, title=translatorDisplayName)= translatorDisplayName.split(" ").map(l => l.at(0)).join("")
|
||||
td(onclick=onclickResponse)
|
||||
td(onclick=onclickResponse)
|
||||
28
server/views/translate-chapter-translator-form.pug
Normal file
28
server/views/translate-chapter-translator-form.pug
Normal file
@@ -0,0 +1,28 @@
|
||||
extend templates/layout.pug
|
||||
|
||||
block content
|
||||
.container
|
||||
.center
|
||||
h1 #{translationChapter.translationArtifactVersion.artifactVersion.artifact.dialect.name} to #{translationChapter.translationArtifactVersion.name}
|
||||
h2= translationChapter.translationArtifactVersion.artifactVersion.artifact.name
|
||||
|
||||
p.flow-text
|
||||
span.chip #{translationChapter.chapter.wordCount.toLocaleString()} words
|
||||
|
||||
p.flow-text Add translator
|
||||
|
||||
|
||||
form.row(action=`/translate/${translationChapter.translationArtifactVersion.id}/chapter/${translationChapter.id}/translator`, method="post")
|
||||
.col.s12
|
||||
.row
|
||||
.input-field.col.s12
|
||||
i.material-icons.prefix translate
|
||||
input#translator-input.autocomplete(type="text", name="translator", required=true)
|
||||
|
||||
label(for="translator-input") Enter translators email
|
||||
//- TODO add other functionality... phone number or username
|
||||
|
||||
|
||||
block additionalScripts
|
||||
script
|
||||
include js/init-translator-autocomplete.js
|
||||
@@ -13,9 +13,13 @@ block content
|
||||
.col.s12.m4
|
||||
|
||||
p.flow-text
|
||||
a.btn-flat.waves-effect Translator ▼
|
||||
a.btn-flat.waves-effect.dropdown-trigger(href=`/translate/${translationChapter.translationArtifactVersion.id}/chapter/${translationChapter.id}/translator`) Translator ▼
|
||||
br
|
||||
if translationChapter.translationChapterTranslators.length > 0
|
||||
span With #{translationChapter.translationChapterTranslators.length} translator(s) assigned
|
||||
each translationChapterTranslator in translationChapter.translationChapterTranslators
|
||||
-
|
||||
const translatorDisplayName = translationChapterTranslator.translator.entityEmail == null ? translationChapterTranslator.translator.name : translationChapterTranslator.translator.entityEmail.email.address
|
||||
span.chip= translatorDisplayName
|
||||
else
|
||||
span No translators assigned yet
|
||||
.col.s12.m4
|
||||
@@ -64,4 +68,8 @@ block content
|
||||
else if translationChunk.translation
|
||||
a.btn.blue(href=`/translate/${translationChapter.translationArtifactVersion.id}/chapter/${translationChapter.id}/t/${translationChunk.index}`) edit
|
||||
else
|
||||
a.btn.black(href=`/translate/${translationChapter.translationArtifactVersion.id}/chapter/${translationChapter.id}/t/${translationChunk.index}`) translate
|
||||
a.btn.black(href=`/translate/${translationChapter.translationArtifactVersion.id}/chapter/${translationChapter.id}/t/${translationChunk.index}`) translate
|
||||
|
||||
block additionalScripts
|
||||
script
|
||||
include js/init-translator-dropdown.js
|
||||
Reference in New Issue
Block a user