Copilot commented on code in PR #348:
URL: 
https://github.com/apache/hugegraph-computer/pull/348#discussion_r3316355985


##########
vermeer/ui/package.json:
##########
@@ -0,0 +1,11 @@
+{
+  "name": "vermeer-ui",
+  "version": "1.0.0",
+  "private": true,
+  "description": "Frontend dependencies for Vermeer UI (downloaded at build 
time for ASF compliance)",
+  "dependencies": {
+    "jquery": "3.5.1",
+    "bootstrap": "4.3.1",
+    "popper.js": "1.14.7"

Review Comment:
   `popper.js` is declared as a dependency in `package.json` but is never 
copied to `ui/ui/lib/` by `scripts/download_ui_assets.sh`, and the HTML pages 
load `bootstrap.min.js` (which does not bundle Popper). Any Bootstrap 4 
components that depend on Popper (tooltips, popovers, dropdowns) will silently 
fail at runtime. Either remove `popper.js` from `package.json` if not needed, 
or add a copy step in the download script and reference it from the HTML pages 
(or switch the script tag to `bootstrap.bundle.min.js`, which is already being 
copied).
   



##########
vermeer/Makefile:
##########
@@ -66,20 +71,25 @@ clean-all: clean
        @rm -rf tools/protoc/*/protoc
        @rm -rf tools/protoc/*/bin
        @rm -rf tools/protoc/*/include
+       @echo "Cleaning downloaded UI assets..."
+       @rm -rf ui/node_modules ui/package-lock.json
+       @rm -rf ui/ui/lib/bootstrap-4.3.1-dist ui/ui/lib/bootstrap4-glyphicons
+       @rm -f ui/ui/lib/jquery-3.5.1.min.js ui/ui/lib/jquery-license

Review Comment:
   The clean-all target hard-codes the version-specific directory names 
(`bootstrap-4.3.1-dist`, `jquery-3.5.1.min.js`) that are also hard-coded in 
`scripts/download_ui_assets.sh`. If the versions in `package.json` are ever 
bumped, these three locations (script, Makefile, and the HTML asset references) 
will drift out of sync and `make clean-all` will leave stale files behind. 
Consider either deleting `ui/ui/lib/` wholesale (preserving the two tracked 
files via the gitignore allow-list) or sourcing the version from a single place.
   



##########
vermeer/build.sh:
##########
@@ -33,6 +33,12 @@ go mod download
 echo "Checking binary dependencies..."
 ./scripts/download_binaries.sh
 
+# Download UI assets if not exist
+echo "Checking UI assets..."
+ if [ ! -d "ui/ui/lib" ] || [ -z "$(ls -A ui/ui/lib 2>/dev/null)" ]; then
+     ./scripts/download_ui_assets.sh
+ fi

Review Comment:
   This `if`/`fi` block is indented with a leading space, which is inconsistent 
with the rest of `build.sh` (top-level statements start at column 0). It is 
also slightly fragile: if `ui/ui/lib/` exists but contains only the two tracked 
files (`functions.js`, `vermeer.css`), the `-z "$(ls -A)"` check evaluates to 
false and the download is skipped, leaving the build to fail later at `go 
generate`. Consider checking for a specific downloaded artifact (e.g. 
`ui/ui/lib/jquery-3.5.1.min.js`) instead.
   



##########
vermeer/Dockerfile:
##########
@@ -15,10 +15,12 @@
 # limitations under the License.
 #
 FROM golang:1.23-alpine AS builder
+RUN apk add --no-cache npm bash curl
 COPY ./ /src/
 WORKDIR /src/
 ENV CGO_ENABLED="0"
-RUN cd asset && go generate
+RUN ./scripts/download_ui_assets.sh && ls -la ui/ui/lib/
+RUN cd asset && go generate && wc -l assets_vfsdata.go

Review Comment:
   These commands include debugging output that doesn't belong in a production 
Dockerfile: `ls -la ui/ui/lib/` after the UI asset download, and `wc -l 
assets_vfsdata.go` after `go generate`. Consider removing them so the image 
build log isn't polluted with one-off diagnostics.
   



##########
vermeer/ui/ui/lib/functions.js:
##########
@@ -0,0 +1,181 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+; (function () {
+    const API_PREFIX = '/api/v1';
+    window.vermeer = {
+        login: function () {
+            const token = $('#admin_token').val();
+            if (!token) {
+                showDelModal('empty token');
+                return;
+            }
+
+            const req = { token: token };
+            postJson('/login', req,
+                function (data) {
+                    console.log(data.message);
+                    location.reload(true);
+                }
+            );
+        },
+        queryGraphs: function () {
+            const $t = $('#graphs_table');
+            $t.empty();
+            const fields = ['space_name', 'name', 'status', 'state', 
'create_time',
+                'update_time', 'use_out_edges', 'use_out_degree'];
+            $t.append('<thead><tr/></thead>');
+            const $tr = $t.find('thead tr');
+            $.each(fields, function (index, field) {
+                $tr.append($('<th/>').text(field));
+            });
+
+            const ok = function (data) {
+                const $tb = $('<tbody/>');
+                $t.append($tb);
+                const rows = data.graphs;
+                $.each(rows, function (index, row) {
+                    $tb.append(toTableRow(fields, row));
+                });
+            };
+
+            get('/graphs', ok);
+        },
+        queryTasks: function () {
+            const $t = $('#tasks_table');
+            $t.empty();
+            const fields = ['id', 'space_name', 'graph_name', 'create_user', 
'task_type',
+                'status', 'state', 'create_time', 'start_time', 'update_time'];
+            $t.append('<thead><tr/></thead>');
+            const $tr = $t.find('thead tr');
+            $.each(fields, function (index, field) {
+                $tr.append($('<th/>').text(field));
+            });
+
+            const ok = function (data) {
+                const $tb = $('<tbody/>');
+                $t.append($tb);
+                const rows = data.tasks;
+                $.each(rows, function (index, row) {
+                    $tb.append(toTableRow(fields, row));
+                });
+            };
+            get('/tasks', ok);
+        }
+
+    };
+
+    function toTableRow(fields, row) {
+        const $row = $('<tr>');
+        $.each(fields, function (index, field) {
+            let value = '';
+
+            if (field.endsWith('_time')) {
+                value = formatDate(row[field]);
+            } else {
+                value = row[field];
+            }
+
+            const $span = $('<span/>').text(value);
+
+            switch (value) {
+                case 'error':
+                    $span.addClass('badge badge-lg badge-danger');
+                    break;
+                case 'incomplete':
+                    $span.addClass('badge badge-lg badge-warning');
+                    break;
+                case 'complete':
+                case 'loaded':
+                case 'disk':
+                    $span.addClass('badge badge-lg badge-success');
+            }
+
+            const $td = $('<td>').append($span);
+            $row.append($td);
+        });
+        return $row;
+    }
+
+    function showDelModal(text) {
+        $('#msg-modal-msg').text(text);
+        $('#msg-modal').modal('show');
+    }
+
+    function get(url, ok, error, caller) {
+        ajax('GET', url, '', ok, error, caller);
+    }
+
+    function postJson(url, data, ok, error, caller) {
+        ajax('POST', url, JSON.stringify(data), ok, error, caller);
+    }
+
+    function ajax(method, url, data, ok, error, caller) {
+        $.ajax({
+            url: API_PREFIX + url,
+            type: method,
+            data: data,
+            contentType: 'application/json',
+            success: function (response) {
+                if (!ok) {
+                    console.log('ajax request successful:', response);
+                    return;
+                }
+                if (caller) {
+                    ok.apply(caller, [response]);
+                } else {
+                    ok(response);
+                }
+            },
+            error: function (err) {
+                if (err.status === 401) {
+                    showDelModal('Login First!');
+                    return;
+                } else {
+                    console.log('ajax request failed:', err);
+                }
+                if (!error) {
+                    let data = JSON.parse(err.responseText);
+                    showDelModal(data.message);
+                    return;
+                }
+                if (caller) {
+                    error.apply(caller, [err]);
+                } else {
+                    error(err);
+                }
+            }
+        });
+    }
+
+    function formatDate(inputDate) {
+        const date = new Date(inputDate);
+        const year = date.getFullYear();
+        const month = (date.getMonth() + 1).toString().padStart(2, '0');
+        const day = date.getDate().toString().padStart(2, '0');
+        const hours = date.getHours().toString().padStart(2, '0');
+        const minutes = date.getMinutes().toString().padStart(2, '0');
+        const seconds = date.getSeconds().toString().padStart(2, '0');
+
+        return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+    }
+
+})();
+
+$(function () {
+    vermeer.queryGraphs ();

Review Comment:
   Stray space before `()` (`vermeer.queryGraphs ();`) is inconsistent with the 
call on the next line (`vermeer.queryTasks();`).
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to