mirror of
https://github.com/Dadido3/Scanyonero.git
synced 2025-06-06 01:10:00 +00:00
Add split function
- Add ServerWebsocketPacketQueueSplit - Add Split method to Queue - Correct automatic separator insertion for newly ingested documents - Rework UI so that entries have their own set of buttons - Refactor occurrences of "document" to "queueEntry"
This commit is contained in:
parent
1bd8be6abf
commit
b5ecf95a7b
7
main.go
7
main.go
@ -58,7 +58,12 @@ func main() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
server.Documents.Lock()
|
||||||
|
|
||||||
var entries []QueueEntry
|
var entries []QueueEntry
|
||||||
|
if len(server.Documents.Documents) > 0 {
|
||||||
|
entries = append(entries, QueueEntry{ID: NewQueueEntryID(), QueueEntryData: QueueEntryDataSeparator{}})
|
||||||
|
}
|
||||||
for _, page := range docPages {
|
for _, page := range docPages {
|
||||||
entries = append(entries, QueueEntry{
|
entries = append(entries, QueueEntry{
|
||||||
ID: NewQueueEntryID(),
|
ID: NewQueueEntryID(),
|
||||||
@ -66,9 +71,7 @@ func main() {
|
|||||||
QueueEntryData: QueueEntryDataPage{Page: &page},
|
QueueEntryData: QueueEntryDataPage{Page: &page},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
entries = append(entries, QueueEntry{ID: NewQueueEntryID(), QueueEntryData: QueueEntryDataSeparator{}})
|
|
||||||
|
|
||||||
server.Documents.Lock()
|
|
||||||
server.Documents.Append(entries...)
|
server.Documents.Append(entries...)
|
||||||
server.Documents.Unlock()
|
server.Documents.Unlock()
|
||||||
}
|
}
|
||||||
|
33
queue.go
33
queue.go
@ -171,15 +171,38 @@ func (d *Queue) Shift(offset int, ids ...QueueEntryID) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Split will add a separator behind every queue entry with the given IDs.
|
||||||
|
//
|
||||||
|
// The Queue must be locked when calling this.
|
||||||
|
func (d *Queue) Split(ids ...QueueEntryID) {
|
||||||
|
for _, id := range ids {
|
||||||
|
if i := slices.IndexFunc(d.Documents, func(e QueueEntry) bool { return e.ID == id }); i >= 0 && i < len(d.Documents)-1 {
|
||||||
|
doc := &d.Documents[i]
|
||||||
|
|
||||||
|
switch d.Documents[i+1].QueueEntryData.(type) {
|
||||||
|
case QueueEntryDataPage:
|
||||||
|
default:
|
||||||
|
// If the next entry is not a page, we will not put a separator here.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch doc.QueueEntryData.(type) {
|
||||||
|
case QueueEntryDataPage:
|
||||||
|
d.InsertAt(i+1, QueueEntry{
|
||||||
|
ID: NewQueueEntryID(),
|
||||||
|
QueueEntryData: QueueEntryDataSeparator{},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// QueueEntryByID returns the QueueEntry with the given ID.
|
// QueueEntryByID returns the QueueEntry with the given ID.
|
||||||
//
|
//
|
||||||
// The Queue must be locked when calling this.
|
// The Queue must be locked when calling this.
|
||||||
func (d *Queue) QueueEntryByID(id QueueEntryID) *QueueEntry {
|
func (d *Queue) QueueEntryByID(id QueueEntryID) *QueueEntry {
|
||||||
for i := range d.Documents {
|
if i := slices.IndexFunc(d.Documents, func(e QueueEntry) bool { return e.ID == id }); i >= 0 {
|
||||||
document := &d.Documents[i]
|
return &d.Documents[i]
|
||||||
if document.ID == id {
|
|
||||||
return document
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -51,7 +51,7 @@ func init() { ServerWebsocketPacketRegister(&ServerWebsocketPacketQueueShiftAt{}
|
|||||||
|
|
||||||
// ServerWebsocketPacketQueueShift represents a shift operation on a document queue list.
|
// ServerWebsocketPacketQueueShift represents a shift operation on a document queue list.
|
||||||
type ServerWebsocketPacketQueueShift struct {
|
type ServerWebsocketPacketQueueShift struct {
|
||||||
IDs []QueueEntryID `json:"ids"` // IDs of the documents.
|
IDs []QueueEntryID `json:"ids"` // IDs of the entries.
|
||||||
Offset int `json:"offset"` // Shift offset.
|
Offset int `json:"offset"` // Shift offset.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,8 +59,8 @@ func (s *ServerWebsocketPacketQueueShift) Type() string { return "QueueShift" }
|
|||||||
|
|
||||||
func init() { ServerWebsocketPacketRegister(&ServerWebsocketPacketQueueShift{}) }
|
func init() { ServerWebsocketPacketRegister(&ServerWebsocketPacketQueueShift{}) }
|
||||||
|
|
||||||
// ServerWebsocketPacketQueueUpdate represents an update operation of documents in a queue list.
|
// ServerWebsocketPacketQueueUpdate represents an update operation of entries in a queue list.
|
||||||
// The receiver should update any of the received documents in their local queue list.
|
// The receiver should update any of the received entries in their local queue list.
|
||||||
type ServerWebsocketPacketQueueUpdate struct {
|
type ServerWebsocketPacketQueueUpdate struct {
|
||||||
Documents []QueueEntry `json:"documents"`
|
Documents []QueueEntry `json:"documents"`
|
||||||
}
|
}
|
||||||
@ -68,3 +68,13 @@ type ServerWebsocketPacketQueueUpdate struct {
|
|||||||
func (s *ServerWebsocketPacketQueueUpdate) Type() string { return "QueueUpdate" }
|
func (s *ServerWebsocketPacketQueueUpdate) Type() string { return "QueueUpdate" }
|
||||||
|
|
||||||
func init() { ServerWebsocketPacketRegister(&ServerWebsocketPacketQueueUpdate{}) }
|
func init() { ServerWebsocketPacketRegister(&ServerWebsocketPacketQueueUpdate{}) }
|
||||||
|
|
||||||
|
// ServerWebsocketPacketQueueSplit represents a "add separator" operation in a queue list.
|
||||||
|
// The split is added behind the given entry IDs.
|
||||||
|
type ServerWebsocketPacketQueueSplit struct {
|
||||||
|
IDs []QueueEntryID `json:"ids"` // IDs of the entries.
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServerWebsocketPacketQueueSplit) Type() string { return "QueueSplit" }
|
||||||
|
|
||||||
|
func init() { ServerWebsocketPacketRegister(&ServerWebsocketPacketQueueSplit{}) }
|
||||||
|
@ -92,6 +92,10 @@ func (s *Server) handleWebSocket(w http.ResponseWriter, r *http.Request) {
|
|||||||
s.Documents.Lock()
|
s.Documents.Lock()
|
||||||
s.Documents.Shift(packet.Offset, packet.IDs...)
|
s.Documents.Shift(packet.Offset, packet.IDs...)
|
||||||
s.Documents.Unlock()
|
s.Documents.Unlock()
|
||||||
|
case *ServerWebsocketPacketQueueSplit:
|
||||||
|
s.Documents.Lock()
|
||||||
|
s.Documents.Split(packet.IDs...)
|
||||||
|
s.Documents.Unlock()
|
||||||
default:
|
default:
|
||||||
log.Printf("Websocket client %q sent unsupported packet type %T.", conn.LocalAddr(), prototype)
|
log.Printf("Websocket client %q sent unsupported packet type %T.", conn.LocalAddr(), prototype)
|
||||||
return
|
return
|
||||||
|
@ -96,6 +96,20 @@ export class API extends EventTarget {
|
|||||||
this.#socket.send(JSON.stringify(message));
|
this.#socket.send(JSON.stringify(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a document queue split request to the server.
|
||||||
|
* @param {...number} ids Document ids.
|
||||||
|
*/
|
||||||
|
queueSplit(...ids) {
|
||||||
|
if (this.#socket.readyState !== WebSocket.OPEN) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {{type: string, payload: import("./model").APIPacketQueueSplit}} */
|
||||||
|
const message = { type: "QueueSplit", payload: { ids: ids } };
|
||||||
|
this.#socket.send(JSON.stringify(message));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {"GET"|"POST"|"DELETE"|"UPDATE"} method
|
* @param {"GET"|"POST"|"DELETE"|"UPDATE"} method
|
||||||
|
@ -14,20 +14,46 @@ export class DocumentQueueEntryPage extends LitElement {
|
|||||||
/** @type {API} */
|
/** @type {API} */
|
||||||
this.api;
|
this.api;
|
||||||
/** @type {import('model').APIQueueEntry} */
|
/** @type {import('model').APIQueueEntry} */
|
||||||
this.document;
|
this.queueEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
static styles = css`
|
static styles = css`
|
||||||
|
:host {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
width: 128px;
|
width: 128px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#buttons {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<img id="image" src=${`/api/queue-entry-page/${this.document.id}/preview`}></img>
|
<img id="image" src=${`/api/queue-entry-page/${this.queueEntry.id}/preview`}></img>
|
||||||
<span>This is a document</span>
|
<div style="flex-grow: 1;">
|
||||||
|
<span>This is a document</span>
|
||||||
|
</div>
|
||||||
|
<div id="buttons">
|
||||||
|
<button @click=${e => this.api.queueShift(-1, this.queueEntry.id)}>▲</button>
|
||||||
|
<button @click=${e => this.api.queueDelete(this.queueEntry.id)}>Delete</button>
|
||||||
|
<button @click=${e => this.api.queueSplit(this.queueEntry.id)}>Split</button>
|
||||||
|
<button @click=${e => this.api.queueShift(1, this.queueEntry.id)}>▼</button>
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,20 +14,38 @@ export class DocumentQueueEntrySeparator extends LitElement {
|
|||||||
/** @type {API} */
|
/** @type {API} */
|
||||||
this.api;
|
this.api;
|
||||||
/** @type {import('model').APIQueueEntry} */
|
/** @type {import('model').APIQueueEntry} */
|
||||||
this.document;
|
this.queueEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
static styles = css`
|
static styles = css`
|
||||||
:host {
|
:host {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: black;
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#buttons {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 8px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
|
<div style="flex-grow: 1; align-self: center;">
|
||||||
|
<hr>
|
||||||
|
</div>
|
||||||
|
<div id="buttons">
|
||||||
|
<button @click=${e => this.api.queueDelete(this.queueEntry.id)}>Delete</button>
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,9 +61,9 @@ export class DocumentQueueEntry extends LitElement {
|
|||||||
let embeddedElement;
|
let embeddedElement;
|
||||||
switch (this.queueEntry.type) {
|
switch (this.queueEntry.type) {
|
||||||
case "Page":
|
case "Page":
|
||||||
embeddedElement = html`<document-queue-entry-page .document=${this.queueEntry} .api=${this.api}></document-queue-entry-page>`; break;
|
embeddedElement = html`<document-queue-entry-page .queueEntry=${this.queueEntry} .api=${this.api}></document-queue-entry-page>`; break;
|
||||||
case "Separator":
|
case "Separator":
|
||||||
embeddedElement = html`<document-queue-entry-separator .document=${this.queueEntry} .api=${this.api}></document-queue-entry-separator>`; break;
|
embeddedElement = html`<document-queue-entry-separator .queueEntry=${this.queueEntry} .api=${this.api}></document-queue-entry-separator>`; break;
|
||||||
default:
|
default:
|
||||||
embeddedElement = html`<span>Unsupported entry type!</span>`
|
embeddedElement = html`<span>Unsupported entry type!</span>`
|
||||||
}
|
}
|
||||||
@ -71,7 +71,6 @@ export class DocumentQueueEntry extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<div id="left-bar">
|
<div id="left-bar">
|
||||||
<input id="checkbox-selected" type="checkbox" .checked=${this.selected} @change=${this.onCheckboxChange}></input>
|
<input id="checkbox-selected" type="checkbox" .checked=${this.selected} @change=${this.onCheckboxChange}></input>
|
||||||
<button id="button-swap" @click=${e => this.api.queueShift(1, this.queueEntry.id)}>⇵</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${embeddedElement}
|
${embeddedElement}
|
||||||
|
4
static/js/model.d.ts
vendored
4
static/js/model.d.ts
vendored
@ -33,6 +33,10 @@ export type APIPacketQueueShift = {
|
|||||||
offset: number;
|
offset: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type APIPacketQueueSplit = {
|
||||||
|
ids: number[];
|
||||||
|
}
|
||||||
|
|
||||||
export type APIEvents = {
|
export type APIEvents = {
|
||||||
queuedeleteat: CustomEvent<APIPacketQueueDeleteAt>;
|
queuedeleteat: CustomEvent<APIPacketQueueDeleteAt>;
|
||||||
queueinsertat: CustomEvent<APIPacketQueueInsertAt>;
|
queueinsertat: CustomEvent<APIPacketQueueInsertAt>;
|
||||||
|
Loading…
Reference in New Issue
Block a user