In some circumstances the item ID might be undefined or empty and the request will fail with a rather cryptic validation error.
```
Aug 03 10:44:54 sn06.galaxyproject.eu gunicorn[2458098]: pydantic.error_wrappers.ValidationError: 2 validation errors for HistoryContentsIndexParams
Aug 03 10:44:54 sn06.galaxyproject.eu gunicorn[2458098]: dataset_details -> 1
Aug 03 10:44:54 sn06.galaxyproject.eu gunicorn[2458098]: Invalid characters in encoded ID (type=value_error)
Aug 03 10:44:54 sn06.galaxyproject.eu gunicorn[2458098]: dataset_details
Aug 03 10:44:54 sn06.galaxyproject.eu gunicorn[2458098]: unhashable type: 'set' (type=type_error)
```
The incoming list of histories contains only summary information for all of them and the current history has additional details that we need.
Since the current history gets updated regularly, there is no harm in skipping the update from the incoming list.
Store webpack build hash in meta.json file, and use that to setup
the cache busting.
This should prevent clients from unnecessarily reloading client bundles
when the server restarts and/or when individual workers finish booting
at staggered intervals.
This became more important with usegalaxy.org not forking off workers
from a preloaded master (so all workers would have the same starttime).
Fixes
https://sentry.galaxyproject.org/share/issue/ff9f4891f34e4308b8183ef604970761/:
```
TypeError: tag_autocomplete_data() got an unexpected keyword argument 'd'
File "uvicorn/protocols/http/h11_impl.py", line 366, in run_asgi
result = await app(self.scope, self.receive, self.send)
File "uvicorn/middleware/proxy_headers.py", line 75, in __call__
return await self.app(scope, receive, send)
File "fastapi/applications.py", line 269, in __call__
await super().__call__(scope, receive, send)
File "starlette/applications.py", line 124, in __call__
await self.middleware_stack(scope, receive, send)
File "starlette/middleware/errors.py", line 184, in __call__
raise exc
File "starlette/middleware/errors.py", line 162, in __call__
await self.app(scope, receive, _send)
File "starlette/middleware/base.py", line 69, in __call__
await response(scope, receive, send)
File "starlette/responses.py", line 260, in __call__
await wrap(partial(self.listen_for_disconnect, receive))
File "anyio/_backends/_asyncio.py", line 662, in __aexit__
raise exceptions[0]
File "starlette/responses.py", line 256, in wrap
await func()
File "starlette/responses.py", line 245, in stream_response
async for chunk in self.body_iterator:
File "starlette/middleware/base.py", line 58, in body_stream
raise app_exc
File "starlette/middleware/base.py", line 36, in coro
await self.app(scope, request.receive, send_stream.send)
File "starlette_context/middleware/raw_middleware.py", line 96, in __call__
await self.app(scope, receive, send_wrapper)
File "starlette/middleware/base.py", line 69, in __call__
await response(scope, receive, send)
File "starlette/responses.py", line 260, in __call__
await wrap(partial(self.listen_for_disconnect, receive))
File "anyio/_backends/_asyncio.py", line 662, in __aexit__
raise exceptions[0]
File "starlette/responses.py", line 256, in wrap
await func()
File "starlette/responses.py", line 245, in stream_response
async for chunk in self.body_iterator:
File "starlette/middleware/base.py", line 58, in body_stream
raise app_exc
File "starlette/middleware/base.py", line 36, in coro
await self.app(scope, request.receive, send_stream.send)
File "starlette/middleware/base.py", line 69, in __call__
await response(scope, receive, send)
File "starlette/responses.py", line 260, in __call__
await wrap(partial(self.listen_for_disconnect, receive))
File "anyio/_backends/_asyncio.py", line 662, in __aexit__
raise exceptions[0]
File "starlette/responses.py", line 256, in wrap
await func()
File "starlette/responses.py", line 245, in stream_response
async for chunk in self.body_iterator:
File "starlette/middleware/base.py", line 58, in body_stream
raise app_exc
File "starlette/middleware/base.py", line 36, in coro
await self.app(scope, request.receive, send_stream.send)
File "starlette/exceptions.py", line 93, in __call__
raise exc
File "starlette/exceptions.py", line 82, in __call__
await self.app(scope, receive, sender)
File "fastapi/middleware/asyncexitstack.py", line 21, in __call__
raise e
File "fastapi/middleware/asyncexitstack.py", line 18, in __call__
await self.app(scope, receive, send)
File "starlette/routing.py", line 670, in __call__
await route.handle(scope, receive, send)
File "starlette/routing.py", line 418, in handle
await self.app(scope, receive, send)
File "a2wsgi/wsgi.py", line 140, in __call__
return await responder(scope, receive, send)
File "a2wsgi/wsgi.py", line 179, in __call__
raise self.exc_info[0].with_traceback(
File "galaxy/web/framework/middleware/error.py", line 165, in __call__
app_iter = self.application(environ, sr_checker)
File "/cvmfs/main.galaxyproject.org/venv/lib/python3.8/site-packages/paste/recursive.py", line 85, in __call__
return self.application(environ, start_response)
File "galaxy/web/framework/middleware/statsd.py", line 29, in __call__
req = self.application(environ, start_response)
File "/cvmfs/main.galaxyproject.org/venv/lib/python3.8/site-packages/paste/httpexceptions.py", line 640, in __call__
return self.application(environ, start_response)
File "galaxy/web/framework/base.py", line 159, in __call__
return self.handle_request(environ, start_response)
File "galaxy/web/framework/base.py", line 244, in handle_request
body = method(trans, **kwargs)
File "galaxy/web/framework/decorators.py", line 84, in decorator
return func(self, trans, *args, **kwargs)
```
You can test this by editing a history tag in the history menu, by
writing `tag;d`, there should be no 500 error on the Galaxy logs.
The mako is gone, this is all client-side. Also updates the link
generated in the legacy history. Fixes
https://sentry.galaxyproject.org/share/issue/99796552da0246ae982c33e2559fb1f7/:
```
TopLevelLookupException: Can't locate template for uri 'dataset/errors.mako'
File "uvicorn/protocols/http/h11_impl.py", line 366, in run_asgi
result = await app(self.scope, self.receive, self.send)
File "uvicorn/middleware/proxy_headers.py", line 75, in __call__
return await self.app(scope, receive, send)
File "fastapi/applications.py", line 269, in __call__
await super().__call__(scope, receive, send)
File "starlette/applications.py", line 124, in __call__
await self.middleware_stack(scope, receive, send)
File "starlette/middleware/errors.py", line 184, in __call__
raise exc
File "starlette/middleware/errors.py", line 162, in __call__
await self.app(scope, receive, _send)
File "starlette/middleware/base.py", line 69, in __call__
await response(scope, receive, send)
File "starlette/responses.py", line 260, in __call__
await wrap(partial(self.listen_for_disconnect, receive))
File "anyio/_backends/_asyncio.py", line 662, in __aexit__
raise exceptions[0]
File "starlette/responses.py", line 256, in wrap
await func()
File "starlette/responses.py", line 245, in stream_response
async for chunk in self.body_iterator:
File "starlette/middleware/base.py", line 58, in body_stream
raise app_exc
File "starlette/middleware/base.py", line 36, in coro
await self.app(scope, request.receive, send_stream.send)
File "starlette_context/middleware/raw_middleware.py", line 96, in __call__
await self.app(scope, receive, send_wrapper)
File "starlette/middleware/base.py", line 69, in __call__
await response(scope, receive, send)
File "starlette/responses.py", line 260, in __call__
await wrap(partial(self.listen_for_disconnect, receive))
File "anyio/_backends/_asyncio.py", line 662, in __aexit__
raise exceptions[0]
File "starlette/responses.py", line 256, in wrap
await func()
File "starlette/responses.py", line 245, in stream_response
async for chunk in self.body_iterator:
File "starlette/middleware/base.py", line 58, in body_stream
raise app_exc
File "starlette/middleware/base.py", line 36, in coro
await self.app(scope, request.receive, send_stream.send)
File "starlette/middleware/base.py", line 69, in __call__
await response(scope, receive, send)
File "starlette/responses.py", line 260, in __call__
await wrap(partial(self.listen_for_disconnect, receive))
File "anyio/_backends/_asyncio.py", line 662, in __aexit__
raise exceptions[0]
File "starlette/responses.py", line 256, in wrap
await func()
File "starlette/responses.py", line 245, in stream_response
async for chunk in self.body_iterator:
File "starlette/middleware/base.py", line 58, in body_stream
raise app_exc
File "starlette/middleware/base.py", line 36, in coro
await self.app(scope, request.receive, send_stream.send)
File "starlette/exceptions.py", line 93, in __call__
raise exc
File "starlette/exceptions.py", line 82, in __call__
await self.app(scope, receive, sender)
File "fastapi/middleware/asyncexitstack.py", line 21, in __call__
raise e
File "fastapi/middleware/asyncexitstack.py", line 18, in __call__
await self.app(scope, receive, send)
File "starlette/routing.py", line 670, in __call__
await route.handle(scope, receive, send)
File "starlette/routing.py", line 418, in handle
await self.app(scope, receive, send)
File "a2wsgi/wsgi.py", line 140, in __call__
return await responder(scope, receive, send)
File "a2wsgi/wsgi.py", line 179, in __call__
raise self.exc_info[0].with_traceback(
File "galaxy/web/framework/middleware/error.py", line 165, in __call__
app_iter = self.application(environ, sr_checker)
File "/cvmfs/main.galaxyproject.org/venv/lib/python3.8/site-packages/paste/recursive.py", line 85, in __call__
return self.application(environ, start_response)
File "galaxy/web/framework/middleware/statsd.py", line 29, in __call__
req = self.application(environ, start_response)
File "/cvmfs/main.galaxyproject.org/venv/lib/python3.8/site-packages/paste/httpexceptions.py", line 640, in __call__
return self.application(environ, start_response)
File "galaxy/web/framework/base.py", line 159, in __call__
return self.handle_request(environ, start_response)
File "galaxy/web/framework/base.py", line 244, in handle_request
body = method(trans, **kwargs)
File "galaxy/webapps/galaxy/controllers/dataset.py", line 99, in errors
return trans.fill_template("dataset/errors.mako", hda=hda)
File "galaxy/webapps/base/webapp.py", line 1095, in fill_template
return self.fill_template_mako(filename, **kwargs)
File "galaxy/webapps/base/webapp.py", line 1099, in fill_template_mako
template = template_lookup.get_template(filename)
File "mako/lookup.py", line 254, in get_template
raise exceptions.TopLevelLookupException(
```