mirror of
				https://github.com/arcan1s/ahriman.git
				synced 2025-10-31 13:53:41 +00:00 
			
		
		
		
	feat: add silent logs reload
This commit is contained in:
		| @ -97,7 +97,7 @@ | ||||
|                     <input id="package-info-refresh-input" type="checkbox" class="form-check-input" value="" checked> | ||||
|                     <label for="package-info-refresh-input" class="form-check-label">update pacman databases</label> | ||||
|  | ||||
|                     <button id="package-info-update-button" type="submit" class="btn btn-success" onclick="packageInfoUpdate()" data-bs-dismiss="modal"><i class="bi bi-play"></i><span class="d-none d-sm-inline"> update</span></button> | ||||
|                     <button id="package-info-update-button" type="submit" class="btn btn-success" onclick="packageInfoUpdate()"><i class="bi bi-play"></i><span class="d-none d-sm-inline"> update</span></button> | ||||
|                     <button id="package-info-remove-button" type="submit" class="btn btn-danger" onclick="packageInfoRemove()" data-bs-dismiss="modal"><i class="bi bi-trash"></i><span class="d-none d-sm-inline"> remove</span></button> | ||||
|                 {% endif %} | ||||
|                 {% if autorefresh_intervals %} | ||||
| @ -315,6 +315,69 @@ | ||||
|     } | ||||
|  | ||||
|     function loadLogs(packageBase, onFailure) { | ||||
|         const sortFn = (left, right) => left.process_id.localeCompare(right.process_id) || left.version.localeCompare(right.version); | ||||
|         const compareFn = (left, right) => left.process_id === right.process_id && left.version === right.version; | ||||
|  | ||||
|         makeRequest( | ||||
|             `/api/v2/packages/${packageBase}/logs`, | ||||
|             { | ||||
|                 query: { | ||||
|                     architecture: repository.architecture, | ||||
|                     head: true, | ||||
|                     repository: repository.repository, | ||||
|                 }, | ||||
|                 convert: response => response.json(), | ||||
|             }, | ||||
|             data => { | ||||
|                 const currentVersions = Array.from(packageInfoLogsVersions.children) | ||||
|                     .map(el => { | ||||
|                         return { | ||||
|                             process_id: el.dataset.processId, | ||||
|                             version: el.dataset.version, | ||||
|                         }; | ||||
|                     }) | ||||
|                     .sort(sortFn); | ||||
|                 const newVersions = data | ||||
|                     .map(el => { | ||||
|                         return { | ||||
|                             process_id: el.process_id, | ||||
|                             version: el.version, | ||||
|                         }; | ||||
|                     }) | ||||
|                     .sort(sortFn); | ||||
|  | ||||
|                 if (currentVersions.equals(newVersions, compareFn)) | ||||
|                     loadLogsActive(packageBase); | ||||
|                 else | ||||
|                     loadLogsAll(packageBase, onFailure); | ||||
|             }, | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     function loadLogsActive(packageBase) { | ||||
|         const activeLogSelector = packageInfoLogsVersions.querySelector(".active"); | ||||
|  | ||||
|         if (activeLogSelector) { | ||||
|             makeRequest( | ||||
|                 `/api/v2/packages/${packageBase}/logs`, | ||||
|                 { | ||||
|                     query: { | ||||
|                         architecture: repository.architecture, | ||||
|                         repository: repository.repository, | ||||
|                         version: activeLogSelector.dataset.version, | ||||
|                         process_id: activeLogSelector.dataset.processId, | ||||
|                     }, | ||||
|                     convert: response => response.json(), | ||||
|                 }, | ||||
|                 data => { | ||||
|                     activeLogSelector.dataset.logs = convertLogs(data); | ||||
|                     activeLogSelector.click(); | ||||
|                 }, | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function loadLogsAll(packageBase, onFailure) { | ||||
|         makeRequest( | ||||
|             `/api/v2/packages/${packageBase}/logs`, | ||||
|             { | ||||
| @ -440,29 +503,6 @@ | ||||
|         packagesAdd(packageBase, [], repository, {refresh: packageInfoRefreshInput.checked}); | ||||
|     } | ||||
|  | ||||
|     function reloadActiveLogs(packageBase) { | ||||
|         const activeLogSelector = packageInfoLogsVersions.querySelector(".active"); | ||||
|  | ||||
|         if (activeLogSelector) { | ||||
|             makeRequest( | ||||
|                 `/api/v2/packages/${packageBase}/logs`, | ||||
|                 { | ||||
|                     query: { | ||||
|                         architecture: repository.architecture, | ||||
|                         repository: repository.repository, | ||||
|                         version: activeLogSelector.dataset.version, | ||||
|                         process_id: activeLogSelector.dataset.processId, | ||||
|                     }, | ||||
|                     convert: response => response.json(), | ||||
|                 }, | ||||
|                 data => { | ||||
|                     activeLogSelector.dataset.logs = convertLogs(data); | ||||
|                     activeLogSelector.click(); | ||||
|                 }, | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function showPackageInfo(packageBase) { | ||||
|         const isPackageBaseSet = packageBase !== undefined; | ||||
|         if (isPackageBaseSet) { | ||||
| @ -502,7 +542,7 @@ | ||||
|                 const packageBase = packageInfoModal.dataset.package; | ||||
|                 // we only poll status and logs here | ||||
|                 loadPackage(packageBase); | ||||
|                 reloadActiveLogs(packageBase); | ||||
|                 loadLogs(packageBase); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
| @ -218,6 +218,21 @@ | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     Array.prototype.equals = function (right, comparator) { | ||||
|         let index = this.length; | ||||
|         if (index !== right.length) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         while (index--) { | ||||
|             if (!comparator(this[index], right[index])) { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     Date.prototype.toISOStringShort = function () { | ||||
|         const pad = number => String(number).padStart(2, "0"); | ||||
|         return `${this.getFullYear()}-${pad(this.getMonth() + 1)}-${pad(this.getDate())} ${pad(this.getHours())}:${pad(this.getMinutes())}:${pad(this.getSeconds())}`; | ||||
|  | ||||
| @ -27,6 +27,9 @@ class LogsSearchSchema(PaginationSchema): | ||||
|     request log search schema | ||||
|     """ | ||||
|  | ||||
|     head = fields.Boolean(metadata={ | ||||
|         "description": "Return versions only without fetching logs themselves", | ||||
|     }) | ||||
|     version = fields.String(metadata={ | ||||
|         "description": "Package version to search", | ||||
|         "example": __version__, | ||||
|  | ||||
| @ -17,7 +17,10 @@ | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
| # | ||||
| import itertools | ||||
|  | ||||
| from aiohttp.web import Response, json_response | ||||
| from dataclasses import replace | ||||
| from typing import ClassVar | ||||
|  | ||||
| from ahriman.models.user_access import UserAccess | ||||
| @ -28,7 +31,8 @@ from ahriman.web.views.status_view_guard import StatusViewGuard | ||||
|  | ||||
|  | ||||
| class LogsView(StatusViewGuard, BaseView): | ||||
|     """ | ||||
|     """        else: | ||||
|  | ||||
|     package logs web view | ||||
|  | ||||
|     Attributes: | ||||
| @ -66,5 +70,14 @@ class LogsView(StatusViewGuard, BaseView): | ||||
|  | ||||
|         logs = self.service(package_base=package_base).package_logs_get(package_base, version, process, limit, offset) | ||||
|  | ||||
|         head = self.request.query.get("head", "false") | ||||
|         # pylint: disable=protected-access | ||||
|         if self.configuration._convert_to_boolean(head):  # type: ignore[attr-defined] | ||||
|             # logs should be sorted already | ||||
|             logs = [ | ||||
|                 replace(next(log_records), message="")  # remove messages | ||||
|                 for _, log_records in itertools.groupby(logs, lambda log_record: log_record.log_record_id) | ||||
|             ] | ||||
|  | ||||
|         response = [log_record.view() for log_record in logs] | ||||
|         return json_response(response) | ||||
|  | ||||
| @ -139,3 +139,41 @@ async def test_get_not_found(client: TestClient, package_ahriman: Package) -> No | ||||
|     response = await client.get(f"/api/v2/packages/{package_ahriman.base}/logs") | ||||
|     assert response.status == 404 | ||||
|     assert not response_schema.validate(await response.json()) | ||||
|  | ||||
|  | ||||
| async def test_get_head(client: TestClient, package_ahriman: Package) -> None: | ||||
|     """ | ||||
|     must return only versions if head parameter is set | ||||
|     """ | ||||
|     await client.post(f"/api/v1/packages/{package_ahriman.base}", | ||||
|                       json={"status": BuildStatusEnum.Success.value, "package": package_ahriman.view()}) | ||||
|     await client.post(f"/api/v1/packages/{package_ahriman.base}/logs", | ||||
|                       json={"created": 42.0, "message": "message 1", "version": "42"}) | ||||
|     await client.post(f"/api/v1/packages/{package_ahriman.base}/logs", | ||||
|                       json={"created": 43.0, "message": "message 2", "version": "42"}) | ||||
|     await client.post(f"/api/v1/packages/{package_ahriman.base}/logs", | ||||
|                       json={"created": 44.0, "message": "message 3", "version": "43"}) | ||||
|     request_schema = pytest.helpers.schema_request(LogsView.get, location="querystring") | ||||
|     response_schema = pytest.helpers.schema_response(LogsView.get) | ||||
|  | ||||
|     payload = {"head": "true"} | ||||
|     assert not request_schema.validate(payload) | ||||
|     response = await client.get(f"/api/v2/packages/{package_ahriman.base}/logs", params=payload) | ||||
|     assert response.status == 200 | ||||
|  | ||||
|     logs = await response.json() | ||||
|     assert not response_schema.validate(logs) | ||||
|     assert logs == [ | ||||
|         { | ||||
|             "created": 42.0, | ||||
|             "message": "", | ||||
|             "version": "42", | ||||
|             "process_id": LogRecordId.DEFAULT_PROCESS_ID, | ||||
|         }, | ||||
|         { | ||||
|             "created": 44.0, | ||||
|             "message": "", | ||||
|             "version": "43", | ||||
|             "process_id": LogRecordId.DEFAULT_PROCESS_ID, | ||||
|         }, | ||||
|     ] | ||||
|  | ||||
		Reference in New Issue
	
	Block a user