pbordescnil commited on
Commit
5083f77
·
1 Parent(s): 39be855

Show search queue position and activity

Browse files
application_neo4j/app.py CHANGED
@@ -287,6 +287,11 @@ def inject_i18n():
287
  "search.progress_stage_completed", "search.progress_stage_failed",
288
  "search.progress_stage_cancelled",
289
  "search.progress_elapsed", "search.progress_items",
 
 
 
 
 
290
  "search.progress_server_percent",
291
  "search.progress_remaining_step", "search.progress_server_note",
292
  "search.progress_connection_error",
@@ -711,6 +716,25 @@ def search_job_status(job_id):
711
  with search_jobs_lock:
712
  stored_job = search_jobs.get(job_id)
713
  job = dict(stored_job) if stored_job else None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
714
  if not job:
715
  return jsonify({"error": "Search job not found"}), 404
716
 
@@ -722,6 +746,14 @@ def search_job_status(job_id):
722
  "elapsed_seconds": max(0, math.floor(now - started_at)) if started_at else 0,
723
  "progress_percent": None,
724
  "remaining_seconds": None,
 
 
 
 
 
 
 
 
725
  "completed_items": job.get("completed_items"),
726
  "total_items": job.get("total_items"),
727
  "result_url": (
 
287
  "search.progress_stage_completed", "search.progress_stage_failed",
288
  "search.progress_stage_cancelled",
289
  "search.progress_elapsed", "search.progress_items",
290
+ "search.progress_queue_title", "search.progress_queue_wait",
291
+ "search.progress_queue_position", "search.progress_queue_ahead_one",
292
+ "search.progress_queue_ahead_many", "search.progress_queue_next",
293
+ "search.progress_queue_running_one", "search.progress_queue_running_many",
294
+ "search.progress_queue_note",
295
  "search.progress_server_percent",
296
  "search.progress_remaining_step", "search.progress_server_note",
297
  "search.progress_connection_error",
 
716
  with search_jobs_lock:
717
  stored_job = search_jobs.get(job_id)
718
  job = dict(stored_job) if stored_job else None
719
+ queued_jobs = sorted(
720
+ (
721
+ (queued_job.get("created_at", 0), queued_job_id)
722
+ for queued_job_id, queued_job in search_jobs.items()
723
+ if queued_job.get("status") == "queued"
724
+ )
725
+ )
726
+ queued_job_ids = [
727
+ queued_job_id for _, queued_job_id in queued_jobs
728
+ ]
729
+ queue_position = (
730
+ queued_job_ids.index(job_id) + 1
731
+ if job_id in queued_job_ids
732
+ else None
733
+ )
734
+ running_jobs = sum(
735
+ queued_job.get("status") == "running"
736
+ for queued_job in search_jobs.values()
737
+ )
738
  if not job:
739
  return jsonify({"error": "Search job not found"}), 404
740
 
 
746
  "elapsed_seconds": max(0, math.floor(now - started_at)) if started_at else 0,
747
  "progress_percent": None,
748
  "remaining_seconds": None,
749
+ "queue_position": queue_position,
750
+ "queued_jobs": len(queued_job_ids),
751
+ "running_jobs": running_jobs,
752
+ "queue_wait_seconds": (
753
+ max(0, math.floor(now - job.get("created_at", now)))
754
+ if job["status"] == "queued"
755
+ else None
756
+ ),
757
  "completed_items": job.get("completed_items"),
758
  "total_items": job.get("total_items"),
759
  "result_url": (
application_neo4j/static/js/search_progress.js CHANGED
@@ -95,6 +95,7 @@
95
  }
96
 
97
  function renderStatus(progress, job) {
 
98
  const stage = progress.querySelector(".search-progress-stage");
99
  const status = progress.querySelector(".search-progress-status");
100
  const note = progress.querySelector(".search-progress-note");
@@ -102,6 +103,92 @@
102
 
103
  stage.textContent = stageLabel(job.stage);
104
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  const details = [
106
  format(
107
  translate("search.progress_elapsed", "Temps écoulé : {seconds} s"),
@@ -208,6 +295,10 @@
208
  elapsed_seconds: 0,
209
  progress_percent: null,
210
  remaining_seconds: null,
 
 
 
 
211
  completed_items: null,
212
  total_items: null,
213
  });
 
95
  }
96
 
97
  function renderStatus(progress, job) {
98
+ const title = progress.querySelector(".search-progress-title");
99
  const stage = progress.querySelector(".search-progress-stage");
100
  const status = progress.querySelector(".search-progress-status");
101
  const note = progress.querySelector(".search-progress-note");
 
103
 
104
  stage.textContent = stageLabel(job.stage);
105
 
106
+ if (job.status === "queued" || job.stage === "queued") {
107
+ title.textContent = translate(
108
+ "search.progress_queue_title",
109
+ "Recherche en file d’attente"
110
+ );
111
+ progress.classList.remove("alert-info", "alert-danger", "alert-secondary");
112
+ progress.classList.add("alert-warning");
113
+
114
+ const queueDetails = [
115
+ format(
116
+ translate(
117
+ "search.progress_queue_wait",
118
+ "Temps d’attente : {seconds} s"
119
+ ),
120
+ { seconds: job.queue_wait_seconds ?? 0 }
121
+ ),
122
+ ];
123
+ if (job.queue_position && job.queued_jobs) {
124
+ queueDetails.push(
125
+ format(
126
+ translate(
127
+ "search.progress_queue_position",
128
+ "Position dans la file : {position}/{total}"
129
+ ),
130
+ {
131
+ position: job.queue_position,
132
+ total: job.queued_jobs,
133
+ }
134
+ )
135
+ );
136
+ const jobsAhead = job.queue_position - 1;
137
+ if (jobsAhead === 0) {
138
+ queueDetails.push(
139
+ translate(
140
+ "search.progress_queue_next",
141
+ "Votre recherche est la prochaine."
142
+ )
143
+ );
144
+ } else {
145
+ queueDetails.push(
146
+ format(
147
+ translate(
148
+ jobsAhead === 1
149
+ ? "search.progress_queue_ahead_one"
150
+ : "search.progress_queue_ahead_many",
151
+ jobsAhead === 1
152
+ ? "1 recherche devant la vôtre"
153
+ : "{count} recherches devant la vôtre"
154
+ ),
155
+ { count: jobsAhead }
156
+ )
157
+ );
158
+ }
159
+ }
160
+ if (job.running_jobs) {
161
+ queueDetails.push(
162
+ format(
163
+ translate(
164
+ job.running_jobs === 1
165
+ ? "search.progress_queue_running_one"
166
+ : "search.progress_queue_running_many",
167
+ job.running_jobs === 1
168
+ ? "1 recherche en cours"
169
+ : "{count} recherches en cours"
170
+ ),
171
+ { count: job.running_jobs }
172
+ )
173
+ );
174
+ }
175
+ status.textContent = queueDetails.join(" · ");
176
+ note.textContent = translate(
177
+ "search.progress_queue_note",
178
+ "La recherche démarrera automatiquement dès qu’une capacité sera disponible."
179
+ );
180
+ bar.style.width = "0%";
181
+ bar.removeAttribute("aria-valuenow");
182
+ return;
183
+ }
184
+
185
+ title.textContent = translate(
186
+ "search.progress_title",
187
+ "Recherche en cours…"
188
+ );
189
+ progress.classList.remove("alert-warning", "alert-danger", "alert-secondary");
190
+ progress.classList.add("alert-info");
191
+
192
  const details = [
193
  format(
194
  translate("search.progress_elapsed", "Temps écoulé : {seconds} s"),
 
295
  elapsed_seconds: 0,
296
  progress_percent: null,
297
  remaining_seconds: null,
298
+ queue_position: null,
299
+ queued_jobs: null,
300
+ running_jobs: null,
301
+ queue_wait_seconds: 0,
302
  completed_items: null,
303
  total_items: null,
304
  });
application_neo4j/translations.py CHANGED
@@ -108,7 +108,7 @@ TRANSLATIONS = {
108
  "search.btn_search": "Rechercher",
109
  "search.btn_search_simple": "Rechercher",
110
  "search.progress_title": "Recherche en cours…",
111
- "search.progress_stage_queued": "En attente du serveur…",
112
  "search.progress_stage_preparing": "Préparation du graphe…",
113
  "search.progress_stage_descendants": "Recherche des descendants…",
114
  "search.progress_stage_ancestors": "Recherche des ascendants…",
@@ -122,6 +122,15 @@ TRANSLATIONS = {
122
  "search.progress_stage_cancelled": "Recherche annulée.",
123
  "search.progress_elapsed": "Temps écoulé : {seconds} s",
124
  "search.progress_items": "Éléments traités par le serveur : {completed}/{total}",
 
 
 
 
 
 
 
 
 
125
  "search.progress_server_percent": "Progression indiquée par le serveur : {percent} %",
126
  "search.progress_remaining_step": "Temps restant estimé pour cette étape : {seconds} s",
127
  "search.progress_server_note": "La progression repose sur les opérations réellement terminées par le serveur.",
@@ -337,7 +346,7 @@ TRANSLATIONS = {
337
  "search.btn_search": "Search",
338
  "search.btn_search_simple": "Search",
339
  "search.progress_title": "Search in progress…",
340
- "search.progress_stage_queued": "Waiting for the server…",
341
  "search.progress_stage_preparing": "Preparing the graph…",
342
  "search.progress_stage_descendants": "Searching descendants…",
343
  "search.progress_stage_ancestors": "Searching ancestors…",
@@ -351,6 +360,15 @@ TRANSLATIONS = {
351
  "search.progress_stage_cancelled": "Search cancelled.",
352
  "search.progress_elapsed": "Elapsed time: {seconds} s",
353
  "search.progress_items": "Items processed by the server: {completed}/{total}",
 
 
 
 
 
 
 
 
 
354
  "search.progress_server_percent": "Progress reported by the server: {percent}%",
355
  "search.progress_remaining_step": "Estimated time remaining for this step: {seconds} s",
356
  "search.progress_server_note": "Progress is based on operations actually completed by the server.",
 
108
  "search.btn_search": "Rechercher",
109
  "search.btn_search_simple": "Rechercher",
110
  "search.progress_title": "Recherche en cours…",
111
+ "search.progress_stage_queued": "En attente d’une capacité de recherche…",
112
  "search.progress_stage_preparing": "Préparation du graphe…",
113
  "search.progress_stage_descendants": "Recherche des descendants…",
114
  "search.progress_stage_ancestors": "Recherche des ascendants…",
 
122
  "search.progress_stage_cancelled": "Recherche annulée.",
123
  "search.progress_elapsed": "Temps écoulé : {seconds} s",
124
  "search.progress_items": "Éléments traités par le serveur : {completed}/{total}",
125
+ "search.progress_queue_title": "Recherche en file d’attente",
126
+ "search.progress_queue_wait": "Temps d’attente : {seconds} s",
127
+ "search.progress_queue_position": "Position dans la file : {position}/{total}",
128
+ "search.progress_queue_ahead_one": "1 recherche devant la vôtre",
129
+ "search.progress_queue_ahead_many": "{count} recherches devant la vôtre",
130
+ "search.progress_queue_next": "Votre recherche est la prochaine.",
131
+ "search.progress_queue_running_one": "1 recherche en cours",
132
+ "search.progress_queue_running_many": "{count} recherches en cours",
133
+ "search.progress_queue_note": "La recherche démarrera automatiquement dès qu’une capacité sera disponible.",
134
  "search.progress_server_percent": "Progression indiquée par le serveur : {percent} %",
135
  "search.progress_remaining_step": "Temps restant estimé pour cette étape : {seconds} s",
136
  "search.progress_server_note": "La progression repose sur les opérations réellement terminées par le serveur.",
 
346
  "search.btn_search": "Search",
347
  "search.btn_search_simple": "Search",
348
  "search.progress_title": "Search in progress…",
349
+ "search.progress_stage_queued": "Waiting for search capacity…",
350
  "search.progress_stage_preparing": "Preparing the graph…",
351
  "search.progress_stage_descendants": "Searching descendants…",
352
  "search.progress_stage_ancestors": "Searching ancestors…",
 
360
  "search.progress_stage_cancelled": "Search cancelled.",
361
  "search.progress_elapsed": "Elapsed time: {seconds} s",
362
  "search.progress_items": "Items processed by the server: {completed}/{total}",
363
+ "search.progress_queue_title": "Search queued",
364
+ "search.progress_queue_wait": "Waiting time: {seconds} s",
365
+ "search.progress_queue_position": "Queue position: {position}/{total}",
366
+ "search.progress_queue_ahead_one": "1 search ahead of yours",
367
+ "search.progress_queue_ahead_many": "{count} searches ahead of yours",
368
+ "search.progress_queue_next": "Your search is next.",
369
+ "search.progress_queue_running_one": "1 search currently running",
370
+ "search.progress_queue_running_many": "{count} searches currently running",
371
+ "search.progress_queue_note": "Your search will start automatically as soon as capacity becomes available.",
372
  "search.progress_server_percent": "Progress reported by the server: {percent}%",
373
  "search.progress_remaining_step": "Estimated time remaining for this step: {seconds} s",
374
  "search.progress_server_note": "Progress is based on operations actually completed by the server.",