Change List.js integration and rename service-icon css

This commit is contained in:
Patrick Jentsch 2023-01-03 17:03:47 +01:00
parent 980b8cc1d3
commit 77b58d03c3
27 changed files with 413 additions and 384 deletions

View File

@ -201,15 +201,15 @@ $color: (
@each $ressource-name, $color-palette in map-get($color, "status") { @each $ressource-name, $color-palette in map-get($color, "status") {
@each $key, $color-code in $color-palette { @each $key, $color-code in $color-palette {
.#{$ressource-name}-status-color[data-#{$ressource-name}-status="#{$key}"] { .#{$ressource-name}-status-color[data-status="#{$key}"] {
background-color: $color-code !important; background-color: $color-code !important;
} }
.#{$ressource-name}-status-color-border[data-#{$ressource-name}-status="#{$key}"] { .#{$ressource-name}-status-color-border[data-status="#{$key}"] {
border-color: $color-code !important; border-color: $color-code !important;
} }
.#{$ressource-name}-status-color-text[data-#{$ressource-name}-status="#{$key}"] { .#{$ressource-name}-status-color-text[data-status="#{$key}"] {
color: $color-code !important; color: $color-code !important;
} }
} }

View File

@ -27,7 +27,7 @@
transform: scale(2); transform: scale(2);
} }
.btn-scale-x2 .nopaque-icons.service-icon { .btn-scale-x2 .nopaque-icons.service-icons {
font-size: 2.5rem; font-size: 2.5rem;
} }
@ -37,17 +37,20 @@ h1 .nopaque-icons, h2 .nopaque-icons, h3 .nopaque-icons, h4 .nopaque-icons, .tab
} }
.corpus-status-text {text-transform: lowercase;} .corpus-status-text, .job-status-text {text-transform: lowercase;}
.corpus-status-text[data-corpus-status]:empty:before {content: attr(data-corpus-status);} .corpus-status-text[data-status]:empty::before, .job-status-text[data-status]:empty::before {content: attr(data-status);}
.job-status-text {text-transform: lowercase;} .service-scheme[data-service="file-setup-pipeline"] .nopaque-icons.service-icons[data-service="inherit"]:empty::before {content: "E";}
.job-status-text[data-job-status]:empty:before {content: attr(data-job-status);} .service-scheme[data-service="tesseract-ocr-pipeline"] .nopaque-icons.service-icons[data-service="inherit"]:empty::before {content: "F";}
.service-scheme[data-service="transkribus-htr-pipeline"] .nopaque-icons.service-icons[data-service="inherit"]:empty::before {content: "F";}
.service-scheme[data-service="spacy-nlp-pipeline"] .nopaque-icons.service-icons[data-service="inherit"]:empty::before {content: "G";}
.service-scheme[data-service="corpus-analysis"] .nopaque-icons.service-icons[data-service="inherit"]:empty::before {content: "H";}
.nopaque-icons.service-icon[data-service="file-setup-pipeline"]:empty:before {content: "E";} .nopaque-icons.service-icons[data-service="file-setup-pipeline"]:empty::before {content: "E";}
.nopaque-icons.service-icon[data-service="tesseract-ocr-pipeline"]:empty:before {content: "F";} .nopaque-icons.service-icons[data-service="tesseract-ocr-pipeline"]:empty::before {content: "F";}
.nopaque-icons.service-icon[data-service="transkribus-htr-pipeline"]:empty:before {content: "F";} .nopaque-icons.service-icons[data-service="transkribus-htr-pipeline"]:empty::before {content: "F";}
.nopaque-icons.service-icon[data-service="spacy-nlp-pipeline"]:empty:before {content: "G";} .nopaque-icons.service-icons[data-service="spacy-nlp-pipeline"]:empty::before {content: "G";}
.nopaque-icons.service-icon[data-service="corpus-analysis"]:empty:before {content: "H";} .nopaque-icons.service-icons[data-service="corpus-analysis"]:empty::before {content: "H";}
.clickable { .clickable {
cursor: pointer !important; cursor: pointer !important;

View File

@ -6,12 +6,12 @@ class CorpusFileList extends RessourceList {
} }
static options = { static options = {
initialHtmlGenerator: (id) => { listContainerInnerHTMLGenerator: (listContainerElement) => {
return ` listContainerElement.innerHTML = `
<div class="input-field"> <div class="input-field">
<i class="material-icons prefix">search</i> <i class="material-icons prefix">search</i>
<input id="${id}-search" class="search" type="search"></input> <input id="${listContainerElement.id}-search" class="search" type="text"></input>
<label for="${id}-search">Search corpus file</label> <label for="${listContainerElement.id}-search">Search corpus file</label>
</div> </div>
<table> <table>
<thead> <thead>
@ -28,19 +28,6 @@ class CorpusFileList extends RessourceList {
<ul class="pagination"></ul> <ul class="pagination"></ul>
`.trim(); `.trim();
}, },
item: `
<tr class="clickable hoverable">
<td><span class="filename"></span></td>
<td><span class="author"></span></td>
<td><span class="title"></span></td>
<td><span class="publishing-year"></span></td>
<td class="right-align">
<a class="action-button btn-floating red waves-effect waves-light" data-action="delete"><i class="material-icons">delete</i></a>
<a class="action-button btn-floating service-color darken waves-effect waves-light" data-action="download" data-service="corpus-analysis"><i class="material-icons">file_download</i></a>
<a class="action-button btn-floating service-color darken waves-effect waves-light" data-action="view" data-service="corpus-analysis"><i class="material-icons">send</i></a>
</td>
</tr>
`.trim(),
ressourceMapper: (corpusFile) => { ressourceMapper: (corpusFile) => {
return { return {
'id': corpusFile.id, 'id': corpusFile.id,
@ -51,20 +38,35 @@ class CorpusFileList extends RessourceList {
'title': corpusFile.title 'title': corpusFile.title
}; };
}, },
sortArgs: ['creation-date', {order: 'desc'}], sortParams: ['creation-date', {order: 'desc'}],
valueNames: [ listjs: {
{data: ['id']}, item: `
{data: ['creation-date']}, <tr class="clickable hoverable">
'author', <td><span class="filename"></span></td>
'filename', <td><span class="author"></span></td>
'publishing-year', <td><span class="title"></span></td>
'title' <td><span class="publishing-year"></span></td>
] <td class="right-align">
<a class="action-button btn-floating red waves-effect waves-light" data-action="delete"><i class="material-icons">delete</i></a>
<a class="action-button btn-floating service-color darken waves-effect waves-light" data-action="download" data-service="corpus-analysis"><i class="material-icons">file_download</i></a>
<a class="action-button btn-floating service-color darken waves-effect waves-light" data-action="view" data-service="corpus-analysis"><i class="material-icons">send</i></a>
</td>
</tr>
`.trim(),
valueNames: [
{data: ['id']},
{data: ['creation-date']},
'author',
'filename',
'publishing-year',
'title'
]
}
}; };
constructor(listElement, options = {}) { constructor(listContainerElement, options={}) {
super(listElement, {...CorpusFileList.options, ...options}); super(listContainerElement, _.merge({}, CorpusFileList.options, options));
this.corpusId = listElement.dataset.corpusId; this.corpusId = listContainerElement.dataset.corpusId;
} }
init(user) { init(user) {
@ -72,10 +74,12 @@ class CorpusFileList extends RessourceList {
} }
onClick(event) { onClick(event) {
let corpusFileElement = event.target.closest('tr');
if (corpusFileElement === null) {return;}
let corpusFileId = corpusFileElement.dataset.id;
if (corpusFileId === undefined) {return;}
let actionButtonElement = event.target.closest('.action-button'); let actionButtonElement = event.target.closest('.action-button');
let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action; let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action;
let corpusFileElement = event.target.closest('tr');
let corpusFileId = corpusFileElement.dataset.id;
switch (action) { switch (action) {
case 'delete': { case 'delete': {
Utils.deleteCorpusFileRequest(this.userId, this.corpusId, corpusFileId); Utils.deleteCorpusFileRequest(this.userId, this.corpusId, corpusFileId);

View File

@ -1,12 +1,4 @@
class CorpusList extends RessourceList { class CorpusList extends RessourceList {
static instances = [];
static getInstance(elem) {
return CorpusList.instances.find((instance) => {
return instance.listjs.list === elem;
});
}
static autoInit() { static autoInit() {
for (let corpusListElement of document.querySelectorAll('.corpus-list:not(.no-autoinit)')) { for (let corpusListElement of document.querySelectorAll('.corpus-list:not(.no-autoinit)')) {
new CorpusList(corpusListElement); new CorpusList(corpusListElement);
@ -14,12 +6,12 @@ class CorpusList extends RessourceList {
} }
static options = { static options = {
initialHtmlGenerator: (id) => { listContainerInnerHTMLGenerator: (listContainerElement) => {
return ` listContainerElement.innerHTML = `
<div class="input-field"> <div class="input-field">
<i class="material-icons prefix">search</i> <i class="material-icons prefix">search</i>
<input id="${id}-search" class="search" type="search"></input> <input id="${listContainerElement.id}-search" class="search" type="text"></input>
<label for="${id}-search">Search corpus</label> <label for="${listContainerElement.id}-search">Search corpus</label>
</div> </div>
<table> <table>
<thead> <thead>
@ -35,17 +27,6 @@ class CorpusList extends RessourceList {
<ul class="pagination"></ul> <ul class="pagination"></ul>
`.trim(); `.trim();
}, },
item: `
<tr class="clickable hoverable">
<td><a class="btn-floating disabled"><i class="material-icons service-color darken" data-service="corpus-analysis">book</i></a></td>
<td><b class="title"></b><br><i class="description"></i></td>
<td><span class="status badge new corpus-status-color corpus-status-text" data-badge-caption=""></span></td>
<td class="right-align">
<a class="action-button btn-floating red waves-effect waves-light" data-action="delete-request"><i class="material-icons">delete</i></a>
<a class="action-button btn-floating service-color darken waves-effect waves-light" data-action="view" data-service="corpus-analysis"><i class="material-icons">send</i></a>
</td>
</tr>
`.trim(),
ressourceMapper: (corpus) => { ressourceMapper: (corpus) => {
return { return {
'id': corpus.id, 'id': corpus.id,
@ -55,19 +36,31 @@ class CorpusList extends RessourceList {
'title': corpus.title 'title': corpus.title
}; };
}, },
sortArgs: ['creation-date', {order: 'desc'}], sortParams: ['creation-date', {order: 'desc'}],
valueNames: [ listjs: {
{data: ['id']}, item: `
{data: ['creation-date']}, <tr class="clickable hoverable">
{name: 'status', attr: 'data-corpus-status'}, <td><a class="btn-floating disabled"><i class="material-icons service-color darken" data-service="corpus-analysis">book</i></a></td>
'description', <td><b class="title"></b><br><i class="description"></i></td>
'title' <td><span class="status badge new corpus-status-color corpus-status-text" data-badge-caption=""></span></td>
] <td class="right-align">
<a class="action-button btn-floating red waves-effect waves-light" data-action="delete-request"><i class="material-icons">delete</i></a>
<a class="action-button btn-floating service-color darken waves-effect waves-light" data-action="view" data-service="corpus-analysis"><i class="material-icons">send</i></a>
</td>
</tr>
`.trim(),
valueNames: [
{data: ['id']},
{data: ['creation-date']},
{name: 'status', attr: 'data-status'},
'description',
'title'
]
}
}; };
constructor(listElement, options = {}) { constructor(listContainerElement, options={}) {
super(listElement, {...CorpusList.options, ...options}); super(listContainerElement, _.merge({}, CorpusList.options, options));
CorpusList.instances.push(this);
} }
init(user) { init(user) {
@ -75,10 +68,12 @@ class CorpusList extends RessourceList {
} }
onClick(event) { onClick(event) {
let corpusElement = event.target.closest('tr');
if (corpusElement === null) {return;}
let corpusId = corpusElement.dataset.id;
if (corpusId === undefined) {return;}
let actionButtonElement = event.target.closest('.action-button'); let actionButtonElement = event.target.closest('.action-button');
let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action; let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action;
let corpusElement = event.target.closest('tr');
let corpusId = corpusElement.dataset.id;
switch (action) { switch (action) {
case 'delete-request': { case 'delete-request': {
Utils.deleteCorpusRequest(this.userId, corpusId); Utils.deleteCorpusRequest(this.userId, corpusId);

View File

@ -6,12 +6,12 @@ class JobInputList extends RessourceList {
} }
static options = { static options = {
initialHtmlGenerator: (id) => { listContainerInnerHTMLGenerator: (listContainerElement) => {
return ` listContainerElement.innerHTML = `
<div class="input-field"> <div class="input-field">
<i class="material-icons prefix">search</i> <i class="material-icons prefix">search</i>
<input id="${id}-search" class="search" type="search"></input> <input id="${listContainerElement.id}-search" class="search" type="text"></input>
<label for="${id}-search">Search job input</label> <label for="${listContainerElement.id}-search">Search job input</label>
</div> </div>
<table> <table>
<thead> <thead>
@ -25,14 +25,6 @@ class JobInputList extends RessourceList {
<ul class="pagination"></ul> <ul class="pagination"></ul>
`.trim(); `.trim();
}, },
item: `
<tr class="clickable hoverable">
<td><span class="filename"></span></td>
<td class="right-align">
<a class="action-button btn-floating waves-effect waves-light" data-action="download"><i class="material-icons">file_download</i></a>
</td>
</tr>
`.trim(),
ressourceMapper: (jobInput) => { ressourceMapper: (jobInput) => {
return { return {
'id': jobInput.id, 'id': jobInput.id,
@ -40,17 +32,27 @@ class JobInputList extends RessourceList {
'filename': jobInput.filename 'filename': jobInput.filename
}; };
}, },
sortArgs: ['filename', {order: 'asc'}], sortParams: ['filename', {order: 'asc'}],
valueNames: [ listjs: {
{data: ['id']}, item: `
{data: ['creation-date']}, <tr class="clickable hoverable">
'filename' <td><span class="filename"></span></td>
] <td class="right-align">
<a class="action-button btn-floating waves-effect waves-light" data-action="download"><i class="material-icons">file_download</i></a>
</td>
</tr>
`.trim(),
valueNames: [
{data: ['id']},
{data: ['creation-date']},
'filename'
]
}
}; };
constructor(listElement, options = {}) { constructor(listContainerElement, options={}) {
super(listElement, {...JobInputList.options, ...options}); super(listContainerElement, _.merge({}, JobInputList.options, options));
this.jobId = listElement.dataset.jobId; this.jobId = listContainerElement.dataset.jobId;
} }
init(user) { init(user) {
@ -58,10 +60,12 @@ class JobInputList extends RessourceList {
} }
onClick(event) { onClick(event) {
let jobInputElement = event.target.closest('tr');
if (jobInputElement === null) {return;}
let jobInputId = jobInputElement.dataset.id;
if (jobInputId === undefined) {return;}
let actionButtonElement = event.target.closest('.action-button'); let actionButtonElement = event.target.closest('.action-button');
let action = actionButtonElement === null ? 'download' : actionButtonElement.dataset.action; let action = actionButtonElement === null ? 'download' : actionButtonElement.dataset.action;
let jobInputElement = event.target.closest('tr');
let jobInputId = jobInputElement.dataset.id;
switch (action) { switch (action) {
case 'download': { case 'download': {
window.location.href = `/jobs/${this.jobId}/inputs/${jobInputId}/download`; window.location.href = `/jobs/${this.jobId}/inputs/${jobInputId}/download`;

View File

@ -6,12 +6,12 @@ class JobList extends RessourceList {
} }
static options = { static options = {
initialHtmlGenerator: (id) => { listContainerInnerHTMLGenerator: (listContainerElement) => {
return ` listContainerElement.innerHTML = `
<div class="input-field"> <div class="input-field">
<i class="material-icons prefix">search</i> <i class="material-icons prefix">search</i>
<input id="${id}-search" class="search" type="search"></input> <input id="${listContainerElement.id}-search" class="search" type="text"></input>
<label for="${id}-search">Search job</label> <label for="${listContainerElement.id}-search">Search job</label>
</div> </div>
<table> <table>
<thead> <thead>
@ -27,44 +27,43 @@ class JobList extends RessourceList {
<ul class="pagination"></ul> <ul class="pagination"></ul>
`.trim(); `.trim();
}, },
item: `
<tr class="clickable hoverable service-color lighten">
<td><a class="btn-floating disabled"><i class="service-1 nopaque-icons service-color darken service-icon"></i></a></td>
<td><b class="title"></b><br><i class="description"></i></td>
<td><span class="status badge new job-status-color job-status-text" data-badge-caption=""></span></td>
<td class="right-align">
<a class="action-button btn-floating red waves-effect waves-light" data-action="delete-request"><i class="material-icons">delete</i></a>
<a class="action-button btn-floating service-color darken waves-effect waves-light service-2" data-action="view"><i class="material-icons">send</i></a>
</td>
</tr>
`.trim(),
ressourceMapper: (job) => { ressourceMapper: (job) => {
return { return {
'id': job.id, 'id': job.id,
'creation-date': job.creation_date, 'creation-date': job.creation_date,
'description': job.description, 'description': job.description,
'service': job.service, 'service': job.service,
'service-1': job.service,
'service-2': job.service,
'status': job.status, 'status': job.status,
'title': job.title 'title': job.title
}; };
}, },
sortArgs: ['creation-date', {order: 'desc'}], sortParams: ['creation-date', {order: 'desc'}],
valueNames: [ listjs: {
{data: ['id']}, item: `
{data: ['creation-date']}, <tr class="clickable hoverable service-scheme">
{data: ['service']}, <td><a class="btn-floating"><i class="nopaque-icons service-icons" data-service="inherit"></i></a></td>
{name: 'service-1', attr: 'data-service'}, <td><b class="title"></b><br><i class="description"></i></td>
{name: 'service-2', attr: 'data-service'}, <td><span class="badge new job-status-color job-status-text status" data-badge-caption=""></span></td>
{name: 'status', attr: 'data-job-status'}, <td class="right-align">
'description', <a class="action-button btn-floating red waves-effect waves-light" data-action="delete-request"><i class="material-icons">delete</i></a>
'title' <a class="action-button btn-floating darken waves-effect waves-light" data-action="view"><i class="material-icons">send</i></a>
] </td>
</tr>
`.trim(),
valueNames: [
{data: ['id']},
{data: ['creation-date']},
{data: ['service']},
{name: 'status', attr: 'data-status'},
'description',
'title'
]
}
}; };
constructor(listElement, options = {}) { constructor(listContainerElement, options={}) {
super(listElement, {...JobList.options, ...options}); super(listContainerElement, _.merge({}, JobList.options, options));
console.log(this);
} }
init(user) { init(user) {
@ -72,10 +71,12 @@ class JobList extends RessourceList {
} }
onClick(event) { onClick(event) {
let jobElement = event.target.closest('tr');
if (jobElement === null) {return;}
let jobId = jobElement.dataset.id;
if (jobId === undefined) {return;}
let actionButtonElement = event.target.closest('.action-button'); let actionButtonElement = event.target.closest('.action-button');
let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action; let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action;
let jobElement = event.target.closest('tr');
let jobId = jobElement.dataset.id;
switch (action) { switch (action) {
case 'delete-request': { case 'delete-request': {
Utils.deleteJobRequest(this.userId, jobId); Utils.deleteJobRequest(this.userId, jobId);

View File

@ -6,12 +6,12 @@ class JobResultList extends RessourceList {
} }
static options = { static options = {
initialHtmlGenerator: (id) => { listContainerInnerHTMLGenerator: (listContainerElement) => {
return ` listContainerElement.innerHTML = `
<div class="input-field"> <div class="input-field">
<i class="material-icons prefix">search</i> <i class="material-icons prefix">search</i>
<input id="${id}-search" class="search" type="search"></input> <input id="${listContainerElement.id}-search" class="search" type="text"></input>
<label for="${id}-search">Search job result</label> <label for="${listContainerElement.id}-search">Search job result</label>
</div> </div>
<table> <table>
<thead> <thead>
@ -26,15 +26,6 @@ class JobResultList extends RessourceList {
<ul class="pagination"></ul> <ul class="pagination"></ul>
`.trim(); `.trim();
}, },
item: `
<tr class="clickable hoverable">
<td><span class="description"></span></td>
<td><span class="filename"></span></td>
<td class="right-align">
<a class="action-button btn-floating waves-effect waves-light" data-action="download"><i class="material-icons">file_download</i></a>
</td>
</tr>
`.trim(),
ressourceMapper: (jobResult) => { ressourceMapper: (jobResult) => {
return { return {
'id': jobResult.id, 'id': jobResult.id,
@ -43,18 +34,29 @@ class JobResultList extends RessourceList {
'filename': jobResult.filename 'filename': jobResult.filename
}; };
}, },
sortArgs: ['filename', {order: 'asc'}], sortParams: ['filename', {order: 'asc'}],
valueNames: [ listjs: {
{data: ['id']}, item: `
{data: ['creation-date']}, <tr class="clickable hoverable">
'description', <td><span class="description"></span></td>
'filename' <td><span class="filename"></span></td>
] <td class="right-align">
<a class="action-button btn-floating waves-effect waves-light" data-action="download"><i class="material-icons">file_download</i></a>
</td>
</tr>
`.trim(),
valueNames: [
{data: ['id']},
{data: ['creation-date']},
'description',
'filename'
]
}
}; };
constructor(listElement, options = {}) { constructor(listContainerElement, options = {}) {
super(listElement, {...JobResultList.options, ...options}); super(listContainerElement, {...JobResultList.options, ...options});
this.jobId = listElement.dataset.jobId; this.jobId = listContainerElement.dataset.jobId;
} }
init(user) { init(user) {
@ -62,10 +64,12 @@ class JobResultList extends RessourceList {
} }
onClick(event) { onClick(event) {
let jobResultElement = event.target.closest('tr');
if (jobResultElement === null) {return;}
let jobResultId = jobResultElement.dataset.id;
if (jobResultId === undefined) {return;}
let actionButtonElement = event.target.closest('.action-button'); let actionButtonElement = event.target.closest('.action-button');
let action = actionButtonElement === null ? 'download' : actionButtonElement.dataset.action; let action = actionButtonElement === null ? 'download' : actionButtonElement.dataset.action;
let jobResultElement = event.target.closest('tr');
let jobResultId = jobResultElement.dataset.id;
switch (action) { switch (action) {
case 'download': { case 'download': {
window.location.href = `/jobs/${this.jobId}/results/${jobResultId}/download`; window.location.href = `/jobs/${this.jobId}/results/${jobResultId}/download`;

View File

@ -6,12 +6,12 @@ class PublicUserList extends RessourceList {
} }
static options = { static options = {
initialHtmlGenerator: (id) => { listContainerInnerHTMLGenerator: (listContainerElement) => {
return ` listContainerElement.innerHTML = `
<div class="input-field"> <div class="input-field">
<i class="material-icons prefix">search</i> <i class="material-icons prefix">search</i>
<input id="${id}-search" class="search" type="search"></input> <input id="${listContainerElement.id}-search" class="search" type="text"></input>
<label for="${id}-search">Search user</label> <label for="${listContainerElement.id}-search">Search user</label>
</div> </div>
<table> <table>
<thead> <thead>
@ -30,19 +30,6 @@ class PublicUserList extends RessourceList {
<ul class="pagination"></ul> <ul class="pagination"></ul>
`.trim(); `.trim();
}, },
item: `
<tr class="clickable hoverable">
<td><img alt="user-image" class="circle responsive-img avatar" style="width:50%"></td>
<td><b><span class="username"></span><b></td>
<td><span class="full-name"></span></td>
<td><span class="location"></span></td>
<td><span class="organization"></span></td>
<td><span class="corpora-online"></span></td>
<td class="right-align">
<a class="action-button btn-floating waves-effect waves-light" data-action="view"><i class="material-icons">send</i></a>
</td>
</tr>
`.trim(),
ressourceMapper: (user) => { ressourceMapper: (user) => {
return { return {
'id': user.id, 'id': user.id,
@ -55,21 +42,36 @@ class PublicUserList extends RessourceList {
'corpora-online': '0' 'corpora-online': '0'
}; };
}, },
sortArgs: ['member-since', {order: 'desc'}], sortParams: ['member-since', {order: 'desc'}],
valueNames: [ listjs: {
{data: ['id']}, item: `
{data: ['member-since']}, <tr class="clickable hoverable">
{name: 'avatar', attr: 'src'}, <td><img alt="user-image" class="circle responsive-img avatar" style="width:50%"></td>
'username', <td><b><span class="username"></span><b></td>
'full-name', <td><span class="full-name"></span></td>
'location', <td><span class="location"></span></td>
'organization', <td><span class="organization"></span></td>
'corpora-online' <td><span class="corpora-online"></span></td>
] <td class="right-align">
<a class="action-button btn-floating waves-effect waves-light" data-action="view"><i class="material-icons">send</i></a>
</td>
</tr>
`.trim(),
valueNames: [
{data: ['id']},
{data: ['member-since']},
{name: 'avatar', attr: 'src'},
'username',
'full-name',
'location',
'organization',
'corpora-online'
]
}
}; };
constructor(listElement, options = {}) { constructor(listContainerElement, options = {}) {
super(listElement, {...PublicUserList.options, ...options}); super(listContainerElement, {...PublicUserList.options, ...options});
} }
init(users) { init(users) {

View File

@ -16,64 +16,69 @@ class RessourceList {
UserList.autoInit(); UserList.autoInit();
} }
static options = {page: 5, pagination: {innerWindow: 2, outerWindow: 2}}; static options = {
listContainerInnerHTMLGenerator: null,
ressourceMapper: null,
sortParams: null,
listjs: {
page: 5,
pagination: {
innerWindow: 2,
outerWindow: 2
}
}
};
constructor(listElement, options = {}) { constructor(listContainerElement, options={}) {
if (!(listElement.hasAttribute('id'))) { let mergedOptions = _.merge({}, RessourceList.options, options);
this.isInitialized = false;
this.listContainerInnerHTMLGenerator = mergedOptions.listContainerInnerHTMLGenerator;
this.ressourceMapper = mergedOptions.ressourceMapper;
this.sortParams = mergedOptions.sortParams;
this.userId = listContainerElement.dataset.userId;
// #region Make sure listElement has an id
if (!listContainerElement.hasAttribute('id')) {
let i; let i;
for (i = 0; true; i++) { for (i = 0; true; i++) {
if (document.querySelector(`#ressource-list-${i}`)) {continue;} if (document.querySelector(`#ressource-list-${i}`)) {continue;}
listElement.id = `ressource-list-${i}`; listContainerElement.id = `ressource-list-${i}`;
break; break;
} }
} }
options = { // #endregion
...RessourceList.options, if (this.listContainerInnerHTMLGenerator !== null && listContainerElement.textContent.trim() === '') {
...options this.listContainerInnerHTMLGenerator(listContainerElement);
} }
if ('ressourceMapper' in options && typeof options.ressourceMapper === 'function') { this.listjs = new List(listContainerElement, mergedOptions.listjs);
this.ressourceMapper = options.ressourceMapper; this.listjs.list.addEventListener('click', (event) => {this.onClick(event)});
delete options.ressourceMapper;
}
if ('initialHtmlGenerator' in options && typeof options.initialHtmlGenerator === 'function') {
this.initialHtmlGenerator = options.initialHtmlGenerator;
listElement.innerHTML = this.initialHtmlGenerator(listElement.id);
delete options.initialHtmlGenerator;
}
if ('sortArgs' in options) {
this.sortArgs = options.sortArgs;
delete options.sortArgs;
}
this.listjs = new List(listElement, {...RessourceList.options, ...options});
this.listjs.list.innerHTML = ` this.listjs.list.innerHTML = `
<tr> <tr>
<td class="row" colspan="100%"> <td colspan="100%">
<div class="col s12">&nbsp;</div> <div class="row">
<div class="col s3 m2 xl1"> <div class="col s12">&nbsp;</div>
<div class="preloader-wrapper active"> <div class="col s3 m2 xl1">
<div class="spinner-layer spinner-green-only"> <div class="preloader-wrapper active">
<div class="circle-clipper left"> <div class="spinner-layer spinner-green-only">
<div class="circle"></div> <div class="circle-clipper left">
</div> <div class="circle"></div>
<div class="gap-patch"> </div>
<div class="circle"></div> <div class="gap-patch">
</div> <div class="circle"></div>
<div class="circle-clipper right"> </div>
<div class="circle"></div> <div class="circle-clipper right">
<div class="circle"></div>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> <div class="col s9 m6 xl5">
<div class="col s9 m6 xl5"> <span class="card-title">Waiting for data...</span>
<span class="card-title">Waiting for data...</span> <p>This list is not initialized yet.</p>
<p>This list is not initialized yet.</p> </div>
</div> </div>
</td> </td>
</tr> </tr>
`.trim(); `.trim();
this.userId = this.listjs.listContainer.dataset.userId;
this.listjs.list.addEventListener('click', (event) => {this.onClick(event)});
this.isInitialized = false;
if (this.userId) { if (this.userId) {
app.subscribeUser(this.userId) app.subscribeUser(this.userId)
.then((response) => { .then((response) => {
@ -113,12 +118,12 @@ class RessourceList {
add(ressources) { add(ressources) {
let values = Array.isArray(ressources) ? ressources : [ressources]; let values = Array.isArray(ressources) ? ressources : [ressources];
if ('ressourceMapper' in this) { if (this.ressourceMapper !== null) {
values = values.map((value) => {return this.ressourceMapper(value);}); values = values.map((value) => {return this.ressourceMapper(value);});
} }
this.listjs.add(values, () => { this.listjs.add(values, () => {
if ('sortArgs' in this) { if (this.sortParams !== null) {
this.listjs.sort(...this.sortArgs); this.listjs.sort(...this.sortParams);
} }
}); });
} }

View File

@ -6,12 +6,12 @@ class SpaCyNLPPipelineModelList extends RessourceList {
} }
static options = { static options = {
initialHtmlGenerator: (id) => { listContainerInnerHTMLGenerator: (listContainerElement) => {
return ` listContainerElement.innerHTML = `
<div class="input-field"> <div class="input-field">
<i class="material-icons prefix">search</i> <i class="material-icons prefix">search</i>
<input id="${id}-search" class="search" type="search"></input> <input id="${listContainerElement.id}-search" class="search" type="text"></input>
<label for="${id}-search">Search SpaCy NLP Pipeline Model</label> <label for="${listContainerElement.id}-search">Search SpaCy NLP Pipeline Model</label>
</div> </div>
<table> <table>
<thead> <thead>
@ -26,26 +26,6 @@ class SpaCyNLPPipelineModelList extends RessourceList {
<ul class="pagination"></ul> <ul class="pagination"></ul>
`.trim(); `.trim();
}, },
item: `
<tr class="clickable hoverable">
<td><b><span class="title"></span> <span class="version"></span></b><br><i><span class="description"></span></i></td>
<td><a class="publisher-url"><span class="publisher"></span></a> (<span class="publishing-year"></span>)<br><a class="publishing-url"><span class="publishing-url-2"></span></a></td>
<td>
<div class="switch action-switch center-align" data-action="share-request">
<span class="share"></span>
<label>
<input type="checkbox" class="is_public">
<span class="lever"></span>
public
</label>
</div>
</td>
<td class="right-align">
<a class="action-button btn-floating red waves-effect waves-light" data-action="delete-request"><i class="material-icons">delete</i></a>
<a class="action-button btn-floating service-color darken waves-effect waves-light service-2" data-action="view"><i class="material-icons">send</i></a>
</td>
</tr>
`.trim(),
ressourceMapper: (spaCyNLPPipelineModel) => { ressourceMapper: (spaCyNLPPipelineModel) => {
return { return {
'id': spaCyNLPPipelineModel.id, 'id': spaCyNLPPipelineModel.id,
@ -62,25 +42,47 @@ class SpaCyNLPPipelineModelList extends RessourceList {
'is_public': spaCyNLPPipelineModel.is_public ? 'True' : 'False' 'is_public': spaCyNLPPipelineModel.is_public ? 'True' : 'False'
}; };
}, },
sortArgs: ['creation-date', {order: 'desc'}], sortParams: ['creation-date', {order: 'desc'}],
valueNames: [ listjs: {
{data: ['id']}, item: `
{data: ['creation-date']}, <tr class="clickable hoverable">
{name: 'publisher-url', attr: 'href'}, <td><b><span class="title"></span> <span class="version"></span></b><br><i><span class="description"></span></i></td>
{name: 'publishing-url', attr: 'href'}, <td><a class="publisher-url"><span class="publisher"></span></a> (<span class="publishing-year"></span>)<br><a class="publishing-url"><span class="publishing-url-2"></span></a></td>
'description', <td>
'publisher', <div class="switch action-switch center-align" data-action="share-request">
'publishing-url-2', <span class="share"></span>
'publishing-year', <label>
'title', <input type="checkbox" class="is_public">
'title-2', <span class="lever"></span>
'version', public
{name: 'is_public', attr: 'data-checked'} </label>
] </div>
</td>
<td class="right-align">
<a class="action-button btn-floating red waves-effect waves-light" data-action="delete-request"><i class="material-icons">delete</i></a>
<a class="action-button btn-floating service-color darken waves-effect waves-light service-2" data-action="view"><i class="material-icons">send</i></a>
</td>
</tr>
`.trim(),
valueNames: [
{data: ['id']},
{data: ['creation-date']},
{name: 'publisher-url', attr: 'href'},
{name: 'publishing-url', attr: 'href'},
'description',
'publisher',
'publishing-url-2',
'publishing-year',
'title',
'title-2',
'version',
{name: 'is_public', attr: 'data-checked'}
]
}
}; };
constructor(listElement, options = {}) { constructor(listContainerElement, options = {}) {
super(listElement, {...SpaCyNLPPipelineModelList.options, ...options}); super(listContainerElement, {...SpaCyNLPPipelineModelList.options, ...options});
this.listjs.list.addEventListener('change', (event) => {this.onChange(event)}); this.listjs.list.addEventListener('change', (event) => {this.onChange(event)});
} }

View File

@ -6,12 +6,12 @@ class TesseractOCRPipelineModelList extends RessourceList {
} }
static options = { static options = {
initialHtmlGenerator: (id) => { listContainerInnerHTMLGenerator: (listContainerElement) => {
return ` listContainerElement.innerHTML = `
<div class="input-field"> <div class="input-field">
<i class="material-icons prefix">search</i> <i class="material-icons prefix">search</i>
<input id="${id}-search" class="search" type="search"></input> <input id="${listContainerElement.id}-search" class="search" type="text"></input>
<label for="${id}-search">Search Tesseract OCR Pipeline Model</label> <label for="${listContainerElement.id}-search">Search Tesseract OCR Pipeline Model</label>
</div> </div>
<table> <table>
<thead> <thead>
@ -26,26 +26,6 @@ class TesseractOCRPipelineModelList extends RessourceList {
<ul class="pagination"></ul> <ul class="pagination"></ul>
`.trim(); `.trim();
}, },
item: `
<tr class="clickable hoverable">
<td><b><span class="title"></span> <span class="version"></span></b><br><i><span class="description"></span></i></td>
<td><a class="publisher-url"><span class="publisher"></span></a> (<span class="publishing-year"></span>)<br><a class="publishing-url"><span class="publishing-url-2"></span></a></td>
<td>
<div class="switch action-switch center-align" data-action="share-request">
<span class="share"></span>
<label>
<input type="checkbox" class="is_public">
<span class="lever"></span>
public
</label>
</div>
</td>
<td class="right-align">
<a class="action-button btn-floating red waves-effect waves-light" data-action="delete-request"><i class="material-icons">delete</i></a>
<a class="action-button btn-floating service-color darken waves-effect waves-light service-2" data-action="view"><i class="material-icons">send</i></a>
</td>
</tr>
`.trim(),
ressourceMapper: (tesseractOCRPipelineModel) => { ressourceMapper: (tesseractOCRPipelineModel) => {
return { return {
'id': tesseractOCRPipelineModel.id, 'id': tesseractOCRPipelineModel.id,
@ -62,25 +42,47 @@ class TesseractOCRPipelineModelList extends RessourceList {
'is_public': tesseractOCRPipelineModel.is_public ? 'True' : 'False' 'is_public': tesseractOCRPipelineModel.is_public ? 'True' : 'False'
}; };
}, },
sortArgs: ['creation-date', {order: 'desc'}], sortParams: ['creation-date', {order: 'desc'}],
valueNames: [ listjs: {
{data: ['id']}, item: `
{data: ['creation-date']}, <tr class="clickable hoverable">
{name: 'publisher-url', attr: 'href'}, <td><b><span class="title"></span> <span class="version"></span></b><br><i><span class="description"></span></i></td>
{name: 'publishing-url', attr: 'href'}, <td><a class="publisher-url"><span class="publisher"></span></a> (<span class="publishing-year"></span>)<br><a class="publishing-url"><span class="publishing-url-2"></span></a></td>
'description', <td>
'publisher', <div class="switch action-switch center-align" data-action="share-request">
'publishing-url-2', <span class="share"></span>
'publishing-year', <label>
'title', <input type="checkbox" class="is_public">
'title-2', <span class="lever"></span>
'version', public
{name: 'is_public', attr: 'data-checked'} </label>
] </div>
</td>
<td class="right-align">
<a class="action-button btn-floating red waves-effect waves-light" data-action="delete-request"><i class="material-icons">delete</i></a>
<a class="action-button btn-floating service-color darken waves-effect waves-light service-2" data-action="view"><i class="material-icons">send</i></a>
</td>
</tr>
`.trim(),
valueNames: [
{data: ['id']},
{data: ['creation-date']},
{name: 'publisher-url', attr: 'href'},
{name: 'publishing-url', attr: 'href'},
'description',
'publisher',
'publishing-url-2',
'publishing-year',
'title',
'title-2',
'version',
{name: 'is_public', attr: 'data-checked'}
]
}
}; };
constructor(listElement, options = {}) { constructor(listContainerElement, options = {}) {
super(listElement, {...TesseractOCRPipelineModelList.options, ...options}); super(listContainerElement, {...TesseractOCRPipelineModelList.options, ...options});
this.listjs.list.addEventListener('change', (event) => {this.onChange(event)}); this.listjs.list.addEventListener('change', (event) => {this.onChange(event)});
} }

View File

@ -6,12 +6,12 @@ class UserList extends RessourceList {
} }
static options = { static options = {
initialHtmlGenerator: (id) => { listContainerInnerHTMLGenerator: (listContainerElement) => {
return ` listContainerElement.innerHTML = `
<div class="input-field"> <div class="input-field">
<i class="material-icons prefix">search</i> <i class="material-icons prefix">search</i>
<input id="${id}-search" class="search" type="search"></input> <input id="${listContainerElement.id}-search" class="search" type="text"></input>
<label for="${id}-search">Search user</label> <label for="${listContainerElement.id}-search">Search user</label>
</div> </div>
<table> <table>
<thead> <thead>
@ -29,20 +29,6 @@ class UserList extends RessourceList {
<ul class="pagination"></ul> <ul class="pagination"></ul>
`.trim(); `.trim();
}, },
item: `
<tr class="clickable hoverable">
<td><span class="id-1"></span></td>
<td><span class="username"></span></td>
<td><span class="email"></span></td>
<td><span class="last-seen"></span></td>
<td><span class="role"></span></td>
<td class="right-align">
<a class="action-button btn-floating red waves-effect waves-light" data-action="delete"><i class="material-icons">delete</i></a>
<a class="action-button btn-floating waves-effect waves-light" data-action="edit"><i class="material-icons">edit</i></a>
<a class="action-button btn-floating waves-effect waves-light" data-action="view"><i class="material-icons">send</i></a>
</td>
</tr>
`.trim(),
ressourceMapper: (user) => { ressourceMapper: (user) => {
return { return {
'id': user.id, 'id': user.id,
@ -54,20 +40,36 @@ class UserList extends RessourceList {
'role': user.role.name 'role': user.role.name
}; };
}, },
sortArgs: ['member-since', {order: 'desc'}], sortParams: ['member-since', {order: 'desc'}],
valueNames: [ listjs: {
{data: ['id']}, item: `
{data: ['member-since']}, <tr class="clickable hoverable">
'email', <td><span class="id-1"></span></td>
'id-1', <td><span class="username"></span></td>
'last-seen', <td><span class="email"></span></td>
'role', <td><span class="last-seen"></span></td>
'username' <td><span class="role"></span></td>
] <td class="right-align">
<a class="action-button btn-floating red waves-effect waves-light" data-action="delete"><i class="material-icons">delete</i></a>
<a class="action-button btn-floating waves-effect waves-light" data-action="edit"><i class="material-icons">edit</i></a>
<a class="action-button btn-floating waves-effect waves-light" data-action="view"><i class="material-icons">send</i></a>
</td>
</tr>
`.trim(),
valueNames: [
{data: ['id']},
{data: ['member-since']},
'email',
'id-1',
'last-seen',
'role',
'username'
]
}
}; };
constructor(listElement, options = {}) { constructor(listContainerElement, options = {}) {
super(listElement, {...UserList.options, ...options}); super(listContainerElement, {...UserList.options, ...options});
} }
init(users) { init(users) {
@ -75,10 +77,12 @@ class UserList extends RessourceList {
} }
onClick(event) { onClick(event) {
let userElement = event.target.closest('tr');
if (userElement === null) {return;}
let userId = userElement.dataset.id;
if (userId === undefined) {return;}
let actionButtonElement = event.target.closest('.action-button'); let actionButtonElement = event.target.closest('.action-button');
let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action; let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action;
let userElement = event.target.closest('tr');
let userId = userElement.dataset.id;
switch (action) { switch (action) {
case 'delete': { case 'delete': {
Utils.deleteUserRequest(userId); Utils.deleteUserRequest(userId);

View File

@ -1,5 +1,6 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/fast-json-patch/3.1.1/fast-json-patch.min.js" integrity="sha512-5uDdefwnzyq4N+SkmMBmekZLZNmc6dLixvVxCdlHBfqpyz0N3bzLdrJ55OLm7QrZmgZuhLGgHLDtJwU6RZoFCA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/fast-json-patch/3.1.1/fast-json-patch.min.js" integrity="sha512-5uDdefwnzyq4N+SkmMBmekZLZNmc6dLixvVxCdlHBfqpyz0N3bzLdrJ55OLm7QrZmgZuhLGgHLDtJwU6RZoFCA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/list.js/2.3.1/list.min.js" integrity="sha512-93wYgwrIFL+b+P3RvYxi/WUFRXXUDSLCT2JQk9zhVGXuS2mHl2axj6d+R6pP+gcU5isMHRj1u0oYE/mWyt/RjA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/list.js/2.3.1/list.min.js" integrity="sha512-93wYgwrIFL+b+P3RvYxi/WUFRXXUDSLCT2JQk9zhVGXuS2mHl2axj6d+R6pP+gcU5isMHRj1u0oYE/mWyt/RjA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.5.1/socket.io.min.js" integrity="sha512-mHO4BJ0ELk7Pb1AzhTi3zvUeRgq3RXVOu9tTRfnA6qOxGK4pG2u57DJYolI4KrEnnLTcH9/J5wNOozRTDaybXg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.5.1/socket.io.min.js" integrity="sha512-mHO4BJ0ELk7Pb1AzhTi3zvUeRgq3RXVOu9tTRfnA6qOxGK4pG2u57DJYolI4KrEnnLTcH9/J5wNOozRTDaybXg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
{%- assets {%- assets
filters='rjsmin', filters='rjsmin',
@ -38,17 +39,19 @@
const currentUserId = {{ current_user.hashid|tojson }}; const currentUserId = {{ current_user.hashid|tojson }};
// Initialize components for current user // Initialize components for current user
app.subscribeUser(currentUserId).catch((error) => {throw JSON.stringify(error);}); app.subscribeUser(currentUserId)
app.getUser(currentUserId, true, true); .catch((error) => {throw JSON.stringify(error);});
app.getUser(currentUserId, true, true)
.catch((error) => {throw JSON.stringify(error);});
{%- endif %} {%- endif %}
// Disable all option elements with no value // Disable all option elements with no value
for (let optionElementWithoutValue of document.querySelectorAll('option[value=""]')) { for (let optionElement of document.querySelectorAll('option[value=""]')) {
optionElementWithoutValue.disabled = true; optionElement.disabled = true;
} }
// Set the data-length attribute on inputs with the maxlength attribute // Set the data-length attribute on textareas/inputs with the maxlength attribute
for (let inputElement of document.querySelectorAll('input[maxlength], textarea[maxlength]')) { for (let inputElement of document.querySelectorAll('textarea[maxlength], input[maxlength]')) {
inputElement.dataset.length = inputElement.getAttribute('maxlength'); inputElement.dataset.length = inputElement.getAttribute('maxlength');
} }
@ -63,7 +66,7 @@
Form.autoInit(); Form.autoInit();
// Display flashed messages // Display flashed messages
for (let flashedMessage of {{ get_flashed_messages(with_categories=True)|tojson }}) { for (let [category, message] of {{ get_flashed_messages(with_categories=True)|tojson }}) {
app.flash(flashedMessage[1], flashedMessage[0]); app.flash(message, message);
} }
</script> </script>

View File

@ -24,13 +24,13 @@
<li><a href="{{ url_for('contributions.contributions') }}"><i class="material-icons">new_label</i>Contribute</a></li> <li><a href="{{ url_for('contributions.contributions') }}"><i class="material-icons">new_label</i>Contribute</a></li>
<li><div class="divider"></div></li> <li><div class="divider"></div></li>
<li><a class="subheader">Processes & Services</a></li> <li><a class="subheader">Processes & Services</a></li>
<li class="service-color service-color-border border-darken" data-service="file-setup-pipeline" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.file_setup_pipeline') }}"><i class="nopaque-icons service-icon" data-service="file-setup-pipeline"></i>File setup</a></li> <li class="service-color service-color-border border-darken" data-service="file-setup-pipeline" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.file_setup_pipeline') }}"><i class="nopaque-icons service-icons" data-service="file-setup-pipeline"></i>File setup</a></li>
<li class="service-color service-color-border border-darken" data-service="tesseract-ocr-pipeline" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.tesseract_ocr_pipeline') }}"><i class="nopaque-icons service-icon" data-service="tesseract-ocr-pipeline"></i>OCR</a></li> <li class="service-color service-color-border border-darken" data-service="tesseract-ocr-pipeline" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.tesseract_ocr_pipeline') }}"><i class="nopaque-icons service-icons" data-service="tesseract-ocr-pipeline"></i>OCR</a></li>
{% if config.NOPAQUE_TRANSKRIBUS_ENABLED %} {% if config.NOPAQUE_TRANSKRIBUS_ENABLED %}
<li class="service-color service-color-border border-darken" data-service="transkribus-htr-pipeline" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.transkribus_htr_pipeline') }}"><i class="nopaque-icons service-icon" data-service="transkribus-htr-pipeline"></i>HTR</a></li> <li class="service-color service-color-border border-darken" data-service="transkribus-htr-pipeline" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.transkribus_htr_pipeline') }}"><i class="nopaque-icons service-icons" data-service="transkribus-htr-pipeline"></i>HTR</a></li>
{% endif %} {% endif %}
<li class="service-color service-color-border border-darken" data-service="spacy-nlp-pipeline" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.spacy_nlp_pipeline') }}"><i class="nopaque-icons service-icon" data-service="spacy-nlp-pipeline"></i>NLP</a></li> <li class="service-color service-color-border border-darken" data-service="spacy-nlp-pipeline" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.spacy_nlp_pipeline') }}"><i class="nopaque-icons service-icons" data-service="spacy-nlp-pipeline"></i>NLP</a></li>
<li class="service-color service-color-border border-darken" data-service="corpus-analysis" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.corpus_analysis') }}"><i class="nopaque-icons service-icon" data-service="corpus-analysis"></i>Corpus analysis</a></li> <li class="service-color service-color-border border-darken" data-service="corpus-analysis" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.corpus_analysis') }}"><i class="nopaque-icons service-icons" data-service="corpus-analysis"></i>Corpus analysis</a></li>
<li><div class="divider"></div></li> <li><div class="divider"></div></li>
<li><a class="subheader">Account</a></li> <li><a class="subheader">Account</a></li>
<li><a href="{{ url_for('settings.settings') }}"><i class="material-icons">settings</i>General Settings</a></li> <li><a href="{{ url_for('settings.settings') }}"><i class="material-icons">settings</i>General Settings</a></li>

View File

@ -13,7 +13,7 @@
<div class="card extension-selector hoverable service-color" data-service="tesseract-ocr-pipeline"> <div class="card extension-selector hoverable service-color" data-service="tesseract-ocr-pipeline">
<a href="{{ url_for('.tesseract_ocr_pipeline_models') }}" style="position: absolute; width: 100%; height: 100%;"></a> <a href="{{ url_for('.tesseract_ocr_pipeline_models') }}" style="position: absolute; width: 100%; height: 100%;"></a>
<div class="card-content"> <div class="card-content">
<span class="card-title" data-service="tesseract-ocr-pipeline"><i class="nopaque-icons service-icon" data-service="tesseract-ocr-pipeline"></i>Tesseract OCR Pipeline Models</span> <span class="card-title" data-service="tesseract-ocr-pipeline"><i class="nopaque-icons service-icons" data-service="tesseract-ocr-pipeline"></i>Tesseract OCR Pipeline Models</span>
<p>Here you can see and edit the models that you have created. You can also create new models.</p> <p>Here you can see and edit the models that you have created. You can also create new models.</p>
</div> </div>
</div> </div>
@ -23,7 +23,7 @@
<div class="card extension-selector hoverable service-color" data-service="spacy-nlp-pipeline"> <div class="card extension-selector hoverable service-color" data-service="spacy-nlp-pipeline">
<a href="{{ url_for('.spacy_nlp_pipeline_models') }}" style="position: absolute; width: 100%; height: 100%;"></a> <a href="{{ url_for('.spacy_nlp_pipeline_models') }}" style="position: absolute; width: 100%; height: 100%;"></a>
<div class="card-content"> <div class="card-content">
<span class="card-title"><i class="nopaque-icons service-icon" data-service="spacy-nlp-pipeline"></i>SpaCy NLP Pipeline Models</span> <span class="card-title"><i class="nopaque-icons service-icons" data-service="spacy-nlp-pipeline"></i>SpaCy NLP Pipeline Models</span>
<p>Here you can see and edit the models that you have created. You can also create new models.</p> <p>Here you can see and edit the models that you have created. You can also create new models.</p>
</div> </div>
</div> </div>
@ -34,7 +34,7 @@
<div class="card extension-selector hoverable service-color" data-service="transkribus-htr-pipeline"> <div class="card extension-selector hoverable service-color" data-service="transkribus-htr-pipeline">
<a href="" style="position: absolute; width: 100%; height: 100%;"></a> <a href="" style="position: absolute; width: 100%; height: 100%;"></a>
<div class="card-content"> <div class="card-content">
<span class="card-title"><i class="nopaque-icons service-icon" data-service="transkribus-htr-pipeline"></i>Transkribus HTR Pipeline Models</span> <span class="card-title"><i class="nopaque-icons service-icons" data-service="transkribus-htr-pipeline"></i>Transkribus HTR Pipeline Models</span>
<p>Here you can see and edit the models that you have created. You can also create new models.</p> <p>Here you can see and edit the models that you have created. You can also create new models.</p>
</div> </div>
</div> </div>

View File

@ -16,7 +16,7 @@
<p class="hide-on-small-only">&nbsp;</p> <p class="hide-on-small-only">&nbsp;</p>
<p class="hide-on-small-only">&nbsp;</p> <p class="hide-on-small-only">&nbsp;</p>
<a class="btn-floating btn-large btn-scale-x2 waves-effect waves-light"> <a class="btn-floating btn-large btn-scale-x2 waves-effect waves-light">
<i class="nopaque-icons service-color darken service-icon" data-service="spacy-nlp-pipeline"></i> <i class="nopaque-icons service-color darken service-icons" data-service="spacy-nlp-pipeline"></i>
</a> </a>
</div> </div>
</div> </div>

View File

@ -16,7 +16,7 @@
<p class="hide-on-small-only">&nbsp;</p> <p class="hide-on-small-only">&nbsp;</p>
<p class="hide-on-small-only">&nbsp;</p> <p class="hide-on-small-only">&nbsp;</p>
<a class="btn-floating btn-large btn-scale-x2 waves-effect waves-light"> <a class="btn-floating btn-large btn-scale-x2 waves-effect waves-light">
<i class="nopaque-icons service-color darken service-icon" data-service="tesseract-ocr-pipeline"></i> <i class="nopaque-icons service-color darken service-icons" data-service="tesseract-ocr-pipeline"></i>
</a> </a>
</div> </div>
</div> </div>

View File

@ -4,7 +4,7 @@
{% block page_content %} {% block page_content %}
<ul class="row tabs no-autoinit" id="corpus-analysis-app-extension-tabs"> <ul class="row tabs no-autoinit" id="corpus-analysis-app-extension-tabs">
<li class="tab col s3"><a class="active" href="#corpus-analysis-app-overview"><i class="nopaque-icons service-icon left" data-service="corpus-analysis"></i>Corpus analysis</a></li> <li class="tab col s3"><a class="active" href="#corpus-analysis-app-overview"><i class="nopaque-icons service-icons left" data-service="corpus-analysis"></i>Corpus analysis</a></li>
<li class="tab col s3"><a href="#concordance-extension-container"><i class="material-icons left">list_alt</i>Concordance</a></li> <li class="tab col s3"><a href="#concordance-extension-container"><i class="material-icons left">list_alt</i>Concordance</a></li>
<li class="tab col s3"><a href="#reader-extension-container"><i class="material-icons left">chrome_reader_mode</i>Reader</a></li> <li class="tab col s3"><a href="#reader-extension-container"><i class="material-icons left">chrome_reader_mode</i>Reader</a></li>
</ul> </ul>

View File

@ -9,7 +9,7 @@
<div class="col s12" data-job-id="{{ job.hashid }}" data-user-id="{{ job.user.hashid }}" id="job-display"> <div class="col s12" data-job-id="{{ job.hashid }}" data-user-id="{{ job.user.hashid }}" id="job-display">
<div class="row"> <div class="row">
<div class="col s8 m9 l10"> <div class="col s8 m9 l10">
<h1 id="title"><i style="font-size: inherit;" class="nopaque-icons service-icon" data-service="{{ job.service }}"></i> <span class="job-title"></span></h1> <h1 id="title"><i style="font-size: inherit;" class="nopaque-icons service-icons" data-service="{{ job.service }}"></i> <span class="job-title"></span></h1>
</div> </div>
<div class="col s4 m3 l2 right-align"> <div class="col s4 m3 l2 right-align">
<p>&nbsp;</p> <p>&nbsp;</p>

View File

@ -82,7 +82,7 @@
<div class="card-panel center-align hoverable"> <div class="card-panel center-align hoverable">
<br> <br>
<a href="{{ url_for('services.file_setup_pipeline') }}" class="btn-floating btn-large waves-effect waves-light" style="transform: scale(2);"> <a href="{{ url_for('services.file_setup_pipeline') }}" class="btn-floating btn-large waves-effect waves-light" style="transform: scale(2);">
<i class="nopaque-icons service-color darken service-icon" data-service="file-setup-pipeline"></i> <i class="nopaque-icons service-color darken service-icons" data-service="file-setup-pipeline"></i>
</a> </a>
<br><br> <br><br>
<p class="service-color-text darken" data-service="file-setup-pipeline"><b>File setup</b></p> <p class="service-color-text darken" data-service="file-setup-pipeline"><b>File setup</b></p>
@ -94,7 +94,7 @@
<div class="card-panel center-align hoverable"> <div class="card-panel center-align hoverable">
<br> <br>
<a href="{{ url_for('services.tesseract_ocr_pipeline') }}" class="btn-floating btn-large waves-effect waves-light" style="transform: scale(2);"> <a href="{{ url_for('services.tesseract_ocr_pipeline') }}" class="btn-floating btn-large waves-effect waves-light" style="transform: scale(2);">
<i class="nopaque-icons service-color darken service-icon" data-service="tesseract-ocr-pipeline" style="font-size: 2.5rem;"></i> <i class="nopaque-icons service-color darken service-icons" data-service="tesseract-ocr-pipeline" style="font-size: 2.5rem;"></i>
</a> </a>
<br><br> <br><br>
<p class="service-color-text darken" data-service="tesseract-ocr-pipeline"><b>Optical Character Recognition</b></p> <p class="service-color-text darken" data-service="tesseract-ocr-pipeline"><b>Optical Character Recognition</b></p>
@ -106,7 +106,7 @@
<div class="card-panel center-align hoverable"> <div class="card-panel center-align hoverable">
<br> <br>
<a href="{{ url_for('services.spacy_nlp_pipeline') }}" class="btn-floating btn-large waves-effect waves-light" style="transform: scale(2);"> <a href="{{ url_for('services.spacy_nlp_pipeline') }}" class="btn-floating btn-large waves-effect waves-light" style="transform: scale(2);">
<i class="nopaque-icons service-color darken service-icon" data-service="spacy-nlp-pipeline" style="font-size: 2.5rem;"></i> <i class="nopaque-icons service-color darken service-icons" data-service="spacy-nlp-pipeline" style="font-size: 2.5rem;"></i>
</a> </a>
<br><br> <br><br>
<p class="service-color-text darken" data-service="spacy-nlp-pipeline"><b>Natural Language Processing</b></p> <p class="service-color-text darken" data-service="spacy-nlp-pipeline"><b>Natural Language Processing</b></p>

View File

@ -220,7 +220,7 @@
<div class="card-panel center-align hoverable"> <div class="card-panel center-align hoverable">
<br> <br>
<a href="{{ url_for('services.file_setup_pipeline') }}" class="btn-floating btn-large waves-effect waves-light" style="transform: scale(2);"> <a href="{{ url_for('services.file_setup_pipeline') }}" class="btn-floating btn-large waves-effect waves-light" style="transform: scale(2);">
<i class="nopaque-icons service-color darken service-icon" data-service="file-setup-pipeline"></i> <i class="nopaque-icons service-color darken service-icons" data-service="file-setup-pipeline"></i>
</a> </a>
<br><br> <br><br>
<p class="service-color-text darken" data-service="file-setup-pipeline"><b>File setup</b></p> <p class="service-color-text darken" data-service="file-setup-pipeline"><b>File setup</b></p>
@ -232,7 +232,7 @@
<div class="card-panel center-align hoverable"> <div class="card-panel center-align hoverable">
<br> <br>
<a href="{{ url_for('services.tesseract_ocr_pipeline') }}" class="btn-floating btn-large waves-effect waves-light" style="transform: scale(2);"> <a href="{{ url_for('services.tesseract_ocr_pipeline') }}" class="btn-floating btn-large waves-effect waves-light" style="transform: scale(2);">
<i class="nopaque-icons service-color darken service-icon" data-service="tesseract-ocr-pipeline" style="font-size: 2.5rem;"></i> <i class="nopaque-icons service-color darken service-icons" data-service="tesseract-ocr-pipeline" style="font-size: 2.5rem;"></i>
</a> </a>
<br><br> <br><br>
<p class="service-color-text darken" data-service="tesseract-ocr-pipeline"><b>Optical Character Recognition</b></p> <p class="service-color-text darken" data-service="tesseract-ocr-pipeline"><b>Optical Character Recognition</b></p>
@ -244,7 +244,7 @@
<div class="card-panel center-align hoverable"> <div class="card-panel center-align hoverable">
<br> <br>
<a href="{{ url_for('services.spacy_nlp_pipeline') }}" class="btn-floating btn-large waves-effect waves-light" style="transform: scale(2);"> <a href="{{ url_for('services.spacy_nlp_pipeline') }}" class="btn-floating btn-large waves-effect waves-light" style="transform: scale(2);">
<i class="nopaque-icons service-color darken service-icon" data-service="spacy-nlp-pipeline" style="font-size: 2.5rem;"></i> <i class="nopaque-icons service-color darken service-icons" data-service="spacy-nlp-pipeline" style="font-size: 2.5rem;"></i>
</a> </a>
<br><br> <br><br>
<p class="service-color-text darken" data-service="spacy-nlp-pipeline"><b>Natural Language Processing</b></p> <p class="service-color-text darken" data-service="spacy-nlp-pipeline"><b>Natural Language Processing</b></p>

View File

@ -77,7 +77,7 @@
<div class="col s12 m6 l3 center-align"> <div class="col s12 m6 l3 center-align">
<p>&nbsp;</p> <p>&nbsp;</p>
<a href="{{ url_for('services.file_setup_pipeline') }}" class="btn-floating btn-large btn-scale-x2 waves-effect waves-light"> <a href="{{ url_for('services.file_setup_pipeline') }}" class="btn-floating btn-large btn-scale-x2 waves-effect waves-light">
<i class="nopaque-icons service-color darken service-icon" data-service="file-setup-pipeline"></i> <i class="nopaque-icons service-color darken service-icons" data-service="file-setup-pipeline"></i>
</a> </a>
<br><br> <br><br>
<p class="service-color-text text-darken" data-service="file-setup-pipeline"><b>File setup</b></p> <p class="service-color-text text-darken" data-service="file-setup-pipeline"><b>File setup</b></p>
@ -86,7 +86,7 @@
<div class="col s12 m6 l3 center-align"> <div class="col s12 m6 l3 center-align">
<p>&nbsp;</p> <p>&nbsp;</p>
<a href="{{ url_for('services.tesseract_ocr_pipeline') }}" class="btn-floating btn-large btn-scale-x2 waves-effect waves-light"> <a href="{{ url_for('services.tesseract_ocr_pipeline') }}" class="btn-floating btn-large btn-scale-x2 waves-effect waves-light">
<i class="nopaque-icons service-color darken service-icon" data-service="tesseract-ocr-pipeline"></i> <i class="nopaque-icons service-color darken service-icons" data-service="tesseract-ocr-pipeline"></i>
</a> </a>
<br><br> <br><br>
<p class="service-color-text text-darken" data-service="tesseract-ocr-pipeline"><b>Optical Character Recognition</b></p> <p class="service-color-text text-darken" data-service="tesseract-ocr-pipeline"><b>Optical Character Recognition</b></p>
@ -95,7 +95,7 @@
<div class="col s12 m6 l3 center-align"> <div class="col s12 m6 l3 center-align">
<p>&nbsp;</p> <p>&nbsp;</p>
<a href="{{ url_for('services.transkribus_htr_pipeline') }}" class="btn-floating btn-large btn-scale-x2 waves-effect waves-light"> <a href="{{ url_for('services.transkribus_htr_pipeline') }}" class="btn-floating btn-large btn-scale-x2 waves-effect waves-light">
<i class="nopaque-icons service-color darken service-icon" data-service="transkribus-htr-pipeline"></i> <i class="nopaque-icons service-color darken service-icons" data-service="transkribus-htr-pipeline"></i>
</a> </a>
<br><br> <br><br>
<p class="service-color-text text-darken" data-service="transkribus-htr-pipeline"><b>Transkribus HTR Pipeline</b></p> <p class="service-color-text text-darken" data-service="transkribus-htr-pipeline"><b>Transkribus HTR Pipeline</b></p>
@ -104,7 +104,7 @@
<div class="col s12 m6 l3 center-align"> <div class="col s12 m6 l3 center-align">
<p>&nbsp;</p> <p>&nbsp;</p>
<a href="{{ url_for('services.spacy_nlp_pipeline') }}" class="btn-floating btn-large btn-scale-x2 waves-effect waves-light"> <a href="{{ url_for('services.spacy_nlp_pipeline') }}" class="btn-floating btn-large btn-scale-x2 waves-effect waves-light">
<i class="nopaque-icons service-color darken service-icon" data-service="spacy-nlp-pipeline"></i> <i class="nopaque-icons service-color darken service-icons" data-service="spacy-nlp-pipeline"></i>
</a> </a>
<br><br> <br><br>
<p class="service-color-text text-darken" data-service="spacy-nlp-pipeline"><b>Natural Language Processing</b></p> <p class="service-color-text text-darken" data-service="spacy-nlp-pipeline"><b>Natural Language Processing</b></p>
@ -113,7 +113,7 @@
<div class="col s12 m6 l3 center-align"> <div class="col s12 m6 l3 center-align">
<p>&nbsp;</p> <p>&nbsp;</p>
<a href="{{ url_for('services.corpus_analysis') }}" class="btn-floating btn-large btn-scale-x2 waves-effect waves-light"> <a href="{{ url_for('services.corpus_analysis') }}" class="btn-floating btn-large btn-scale-x2 waves-effect waves-light">
<i class="nopaque-icons service-color darken service-icon" data-service="corpus-analysis"></i> <i class="nopaque-icons service-color darken service-icons" data-service="corpus-analysis"></i>
</a> </a>
<br><br> <br><br>
<p class="service-color-text text-darken" data-service="corpus-analysis"><b>Corpus analysis</b></p> <p class="service-color-text text-darken" data-service="corpus-analysis"><b>Corpus analysis</b></p>

View File

@ -13,7 +13,7 @@
<div class="col s12 m3 push-m9"> <div class="col s12 m3 push-m9">
<div class="center-align"> <div class="center-align">
<a class="btn-floating btn-large btn-scale-x2 waves-effect waves-light" style="transform: scale(2);"> <a class="btn-floating btn-large btn-scale-x2 waves-effect waves-light" style="transform: scale(2);">
<i class="nopaque-icons service-color darken service-icon" data-service="corpus-analysis"></i> <i class="nopaque-icons service-color darken service-icons" data-service="corpus-analysis"></i>
</a> </a>
</div> </div>
</div> </div>

View File

@ -16,7 +16,7 @@
<p class="hide-on-small-only">&nbsp;</p> <p class="hide-on-small-only">&nbsp;</p>
<p class="hide-on-small-only">&nbsp;</p> <p class="hide-on-small-only">&nbsp;</p>
<a class="btn-floating btn-large btn-scale-x2 waves-effect waves-light"> <a class="btn-floating btn-large btn-scale-x2 waves-effect waves-light">
<i class="nopaque-icons service-color darken service-icon" data-service="file-setup-pipeline"></i> <i class="nopaque-icons service-color darken service-icons" data-service="file-setup-pipeline"></i>
</a> </a>
</div> </div>
</div> </div>

View File

@ -16,7 +16,7 @@
<p class="hide-on-small-only">&nbsp;</p> <p class="hide-on-small-only">&nbsp;</p>
<p class="hide-on-small-only">&nbsp;</p> <p class="hide-on-small-only">&nbsp;</p>
<a class="btn-floating btn-large btn-scale-x2 waves-effect waves-light"> <a class="btn-floating btn-large btn-scale-x2 waves-effect waves-light">
<i class="nopaque-icons service-color darken service-icon" data-service="spacy-nlp-pipeline"></i> <i class="nopaque-icons service-color darken service-icons" data-service="spacy-nlp-pipeline"></i>
</a> </a>
</div> </div>
</div> </div>

View File

@ -16,7 +16,7 @@
<p class="hide-on-small-only">&nbsp;</p> <p class="hide-on-small-only">&nbsp;</p>
<p class="hide-on-small-only">&nbsp;</p> <p class="hide-on-small-only">&nbsp;</p>
<a class="btn-floating btn-large btn-scale-x2 waves-effect waves-light"> <a class="btn-floating btn-large btn-scale-x2 waves-effect waves-light">
<i class="nopaque-icons service-color darken service-icon" data-service="tesseract-ocr-pipeline"></i> <i class="nopaque-icons service-color darken service-icons" data-service="tesseract-ocr-pipeline"></i>
</a> </a>
</div> </div>
</div> </div>

View File

@ -16,7 +16,7 @@
<p class="hide-on-small-only">&nbsp;</p> <p class="hide-on-small-only">&nbsp;</p>
<p class="hide-on-small-only">&nbsp;</p> <p class="hide-on-small-only">&nbsp;</p>
<a class="btn-floating btn-large btn-scale-x2 waves-effect waves-light"> <a class="btn-floating btn-large btn-scale-x2 waves-effect waves-light">
<i class="nopaque-icons service-color darken service-icon" data-service="transkribus-htr-pipeline"></i> <i class="nopaque-icons service-color darken service-icons" data-service="transkribus-htr-pipeline"></i>
</a> </a>
</div> </div>
</div> </div>