web server
This commit is contained in:
63
web-server/views/partials/edit-app-modal.ejs
Normal file
63
web-server/views/partials/edit-app-modal.ejs
Normal file
@@ -0,0 +1,63 @@
|
||||
<div class="modal-backdrop" id="editAppModal" role="dialog" aria-modal="true" aria-labelledby="editAppTitle">
|
||||
<div class="modal-content wide">
|
||||
<div class="modal-header">
|
||||
<h3 id="editAppTitle">Sửa Application</h3>
|
||||
<button class="icon-button subtle" type="button" aria-label="Đóng modal" data-modal-close>
|
||||
<span class="material-symbols-outlined">close</span>
|
||||
</button>
|
||||
</div>
|
||||
<form id="editAppForm" class="modal-form" method="post" action="/applications">
|
||||
<input type="hidden" name="returnTo" value="<%= currentPath || '/applications' %>">
|
||||
<div class="form-grid">
|
||||
<label class="form-field">
|
||||
<span>App code</span>
|
||||
<input type="text" name="appCode" required data-edit-app-field="appCode">
|
||||
</label>
|
||||
<label class="form-field">
|
||||
<span>Version</span>
|
||||
<input type="text" name="appVersion" required data-edit-app-field="appVersion">
|
||||
</label>
|
||||
<label class="form-field">
|
||||
<span>Status</span>
|
||||
<select name="status" data-edit-app-field="status">
|
||||
<option value="Draft">Draft</option>
|
||||
<option value="Released">Released</option>
|
||||
<option value="Archived">Archived</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="form-field full">
|
||||
<span>App name</span>
|
||||
<input type="text" name="appName" required data-edit-app-field="appName">
|
||||
</label>
|
||||
<label class="form-field full">
|
||||
<span>Notes</span>
|
||||
<textarea name="notes" data-edit-app-field="notes"></textarea>
|
||||
</label>
|
||||
</div>
|
||||
<div class="modal-mini-table">
|
||||
<% packages.forEach((item) => { %>
|
||||
<label>
|
||||
<input class="checkbox" type="checkbox" name="packageIds" value="<%= item.id %>" data-edit-app-package="<%= item.id %>">
|
||||
<span>
|
||||
<strong><%= item.name %></strong>
|
||||
<small><%= item.code %></small>
|
||||
</span>
|
||||
<select class="mini-select" name="version_<%= item.id %>" data-edit-app-version="<%= item.id %>">
|
||||
<option value="">Latest/default</option>
|
||||
<% item.versions.forEach((version) => { %>
|
||||
<option value="<%= version.id %>"><%= version.version %></option>
|
||||
<% }) %>
|
||||
</select>
|
||||
</label>
|
||||
<% }) %>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button class="btn btn-secondary" type="button" data-modal-close>Hủy</button>
|
||||
<button class="btn btn-primary" type="submit">
|
||||
<span class="material-symbols-outlined">save</span>
|
||||
Lưu
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
78
web-server/views/partials/package-modal.ejs
Normal file
78
web-server/views/partials/package-modal.ejs
Normal file
@@ -0,0 +1,78 @@
|
||||
<div class="modal-backdrop" id="uploadPackageModal" role="dialog" aria-modal="true" aria-labelledby="uploadPackageTitle">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3 id="uploadPackageTitle">Upload package</h3>
|
||||
<button class="icon-button subtle" type="button" aria-label="Đóng modal" data-modal-close>
|
||||
<span class="material-symbols-outlined">close</span>
|
||||
</button>
|
||||
</div>
|
||||
<form class="modal-form" action="/packages" method="post" enctype="multipart/form-data">
|
||||
<div class="form-grid">
|
||||
<label class="form-field">
|
||||
<span>Package code</span>
|
||||
<input type="text" name="packageCode" placeholder="NAV-STACK" required>
|
||||
</label>
|
||||
<label class="form-field">
|
||||
<span>Package type</span>
|
||||
<select name="packageType">
|
||||
<option value="deb">.deb</option>
|
||||
<option value="docker">Docker</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="form-field full">
|
||||
<span>Package name</span>
|
||||
<input type="text" name="packageName" placeholder="Navigation Stack" required>
|
||||
</label>
|
||||
<label class="form-field full">
|
||||
<span>Description</span>
|
||||
<input type="text" name="description" placeholder="Mô tả ngắn về package">
|
||||
</label>
|
||||
<label class="form-field">
|
||||
<span>Version</span>
|
||||
<input type="text" name="version" placeholder="1.0.0" required>
|
||||
</label>
|
||||
<label class="form-field">
|
||||
<span>Release date</span>
|
||||
<input type="date" name="releaseDate" value="2026-05-19">
|
||||
</label>
|
||||
<div class="form-field full">
|
||||
<span>Package file</span>
|
||||
<div class="file-dropzone" data-file-dropzone>
|
||||
<input class="file-input" type="file" name="packageFile" accept=".deb,.tar,.tar.gz,.tgz,.zip,.gz" data-file-input>
|
||||
<div class="file-dropzone-content">
|
||||
<span class="material-symbols-outlined">upload_file</span>
|
||||
<strong>Kéo file vào đây hoặc chọn từ máy</strong>
|
||||
<small>Hỗ trợ .deb, .tar, .tgz, .zip cho package hoặc Docker image export</small>
|
||||
<button class="btn btn-secondary" type="button" data-file-browse>
|
||||
<span class="material-symbols-outlined">attach_file</span>
|
||||
Chọn file
|
||||
</button>
|
||||
</div>
|
||||
<div class="file-preview" data-file-preview hidden>
|
||||
<span class="material-symbols-outlined">draft</span>
|
||||
<div>
|
||||
<strong data-file-name>Chưa chọn file</strong>
|
||||
<small data-file-meta></small>
|
||||
</div>
|
||||
<button class="icon-button subtle" type="button" title="Bỏ file" aria-label="Bỏ file đã chọn" data-file-clear>
|
||||
<span class="material-symbols-outlined">close</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<label class="form-field full">
|
||||
<span>Docker image/tag</span>
|
||||
<input type="text" name="dockerImage" placeholder="registry.local/robot/fleet-agent:1.9.0">
|
||||
</label>
|
||||
<label class="form-field full">
|
||||
<span>Change log</span>
|
||||
<textarea name="changeLog" placeholder="Ghi chú thay đổi"></textarea>
|
||||
</label>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button class="btn btn-secondary" type="button" data-modal-close>Hủy</button>
|
||||
<button class="btn btn-primary" type="submit">Upload</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
61
web-server/views/partials/page-end.ejs
Normal file
61
web-server/views/partials/page-end.ejs
Normal file
@@ -0,0 +1,61 @@
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<% if (currentUser && currentUser.role === 'User') { %>
|
||||
<div id="profileModal" class="modal-backdrop" role="dialog" aria-modal="true" aria-labelledby="profileModalTitle">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3 id="profileModalTitle">Thông tin cá nhân</h3>
|
||||
<button class="icon-button subtle" type="button" data-modal-close aria-label="Đóng">
|
||||
<span class="material-symbols-outlined">close</span>
|
||||
</button>
|
||||
</div>
|
||||
<form class="modal-form" method="post" action="/profile" data-profile-form>
|
||||
<input type="hidden" name="returnTo" value="<%= currentPath || '/' %>">
|
||||
<div class="profile-summary">
|
||||
<div class="profile-avatar"><%= currentUser.name.charAt(0) %></div>
|
||||
<div>
|
||||
<strong><%= currentUser.name %></strong>
|
||||
<span><%= currentUser.username %></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-stack">
|
||||
<label class="form-field">
|
||||
<span>Fullname</span>
|
||||
<input type="text" name="fullName" value="<%= currentUser.fullName || '' %>" autocomplete="name">
|
||||
</label>
|
||||
<label class="form-field">
|
||||
<span>Email mới</span>
|
||||
<input type="email" name="email" value="<%= currentUser.email || '' %>" autocomplete="email" required data-profile-email>
|
||||
</label>
|
||||
<label class="form-field">
|
||||
<span>Confirm email mới</span>
|
||||
<input type="email" name="confirmEmail" value="<%= currentUser.email || '' %>" autocomplete="email" required data-profile-confirm-email>
|
||||
<small class="field-feedback" data-profile-feedback="email"></small>
|
||||
</label>
|
||||
<label class="form-field">
|
||||
<span>Mật khẩu mới</span>
|
||||
<input type="password" name="newPassword" minlength="8" autocomplete="new-password" data-profile-new-password>
|
||||
</label>
|
||||
<label class="form-field">
|
||||
<span>Xác nhận mật khẩu mới</span>
|
||||
<input type="password" name="confirmPassword" minlength="8" autocomplete="new-password" data-profile-confirm-password>
|
||||
<small class="field-feedback" data-profile-feedback="password"></small>
|
||||
</label>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button class="btn btn-secondary" type="button" data-modal-close>Hủy</button>
|
||||
<button class="btn btn-primary" type="submit">
|
||||
<span class="material-symbols-outlined">save</span>
|
||||
Lưu
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
<script src="/vendor/notiflix/notiflix-<%= notiflixVersion %>.min.js"></script>
|
||||
<script src="/js/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
87
web-server/views/partials/page-start.ejs
Normal file
87
web-server/views/partials/page-start.ejs
Normal file
@@ -0,0 +1,87 @@
|
||||
<!doctype html>
|
||||
<html lang="vi">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title><%= title %> | Robot Installer</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/vendor/notiflix/notiflix-<%= notiflixVersion %>.min.css">
|
||||
<link rel="stylesheet" href="/css/styles.css">
|
||||
</head>
|
||||
<body class="app-shell" <% if (notice) { %>data-notice-type="<%= notice.type %>" data-notice="<%= notice.message %>"<% } %>>
|
||||
<aside id="appSidebar" class="sidebar" aria-label="Main navigation">
|
||||
<div class="brand-block">
|
||||
<div class="brand-mark">
|
||||
<span class="material-symbols-outlined">precision_manufacturing</span>
|
||||
</div>
|
||||
<div class="brand-copy">
|
||||
<strong>Robot Installer</strong>
|
||||
<span>Package Console</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="nav-section" aria-label="Workspace">
|
||||
<span class="nav-label">Workspace</span>
|
||||
<% navItems.forEach((item) => { %>
|
||||
<a href="<%= item.href %>" class="nav-item <%= active === item.id ? 'active' : '' %>">
|
||||
<span class="material-symbols-outlined"><%= item.icon %></span>
|
||||
<span><%= item.label %></span>
|
||||
</a>
|
||||
<% }) %>
|
||||
</nav>
|
||||
|
||||
<div class="sidebar-status">
|
||||
<span class="status-dot"></span>
|
||||
<div>
|
||||
<strong>SQL Server</strong>
|
||||
<span>172.20.235.176</span>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<button id="sidebarBackdrop" type="button" aria-label="Đóng menu"></button>
|
||||
|
||||
<main id="appMain" class="main-shell">
|
||||
<header class="topbar">
|
||||
<div class="topbar-left">
|
||||
<button id="mobileMenuBtn" class="icon-button" type="button" aria-label="Mở menu" aria-expanded="false">
|
||||
<span class="material-symbols-outlined">menu</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="topbar-actions">
|
||||
<button class="icon-button" type="button" title="Đồng bộ dữ liệu" data-refresh-page>
|
||||
<span class="material-symbols-outlined">sync</span>
|
||||
</button>
|
||||
<button class="icon-button" type="button" title="Thông báo" data-toast="Chưa có thông báo mới">
|
||||
<span class="material-symbols-outlined">notifications</span>
|
||||
</button>
|
||||
<% if (currentUser.role === 'User') { %>
|
||||
<button class="profile-chip profile-chip-button" type="button" title="Cập nhật thông tin cá nhân" aria-label="Cập nhật thông tin cá nhân" data-modal-open="profileModal">
|
||||
<span class="profile-avatar"><%= currentUser.name.charAt(0) %></span>
|
||||
<span class="profile-meta">
|
||||
<strong><%= currentUser.name %></strong>
|
||||
<span><%= currentUser.role %></span>
|
||||
</span>
|
||||
</button>
|
||||
<% } else { %>
|
||||
<div class="profile-chip">
|
||||
<span class="profile-avatar"><%= currentUser.name.charAt(0) %></span>
|
||||
<span class="profile-meta">
|
||||
<strong><%= currentUser.name %></strong>
|
||||
<span><%= currentUser.role %></span>
|
||||
</span>
|
||||
</div>
|
||||
<% } %>
|
||||
<form class="logout-form" method="post" action="/logout">
|
||||
<button class="icon-button" type="submit" title="Đăng xuất" aria-label="Đăng xuất">
|
||||
<span class="material-symbols-outlined">logout</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div id="mainContent" class="main-content">
|
||||
67
web-server/views/partials/update-package-modal.ejs
Normal file
67
web-server/views/partials/update-package-modal.ejs
Normal file
@@ -0,0 +1,67 @@
|
||||
<div class="modal-backdrop" id="updatePackageModal" role="dialog" aria-modal="true" aria-labelledby="updatePackageTitle">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3 id="updatePackageTitle">Update package version</h3>
|
||||
<button class="icon-button subtle" type="button" aria-label="Đóng modal" data-modal-close>
|
||||
<span class="material-symbols-outlined">close</span>
|
||||
</button>
|
||||
</div>
|
||||
<form class="modal-form" action="/package-versions" method="post" enctype="multipart/form-data">
|
||||
<div class="form-grid">
|
||||
<label class="form-field full">
|
||||
<span>Package</span>
|
||||
<select name="packageId" required>
|
||||
<% packages.forEach((item) => { %>
|
||||
<option value="<%= item.id %>" <%= typeof packageItem !== 'undefined' && packageItem.id === item.id ? 'selected' : '' %>><%= item.code %> - <%= item.name %></option>
|
||||
<% }) %>
|
||||
</select>
|
||||
</label>
|
||||
<label class="form-field">
|
||||
<span>New version</span>
|
||||
<input type="text" name="version" placeholder="2.5.0" required>
|
||||
</label>
|
||||
<label class="form-field">
|
||||
<span>Release date</span>
|
||||
<input type="date" name="releaseDate" value="2026-05-19">
|
||||
</label>
|
||||
<div class="form-field full">
|
||||
<span>Package file</span>
|
||||
<div class="file-dropzone" data-file-dropzone>
|
||||
<input class="file-input" type="file" name="packageFile" accept=".deb,.tar,.tar.gz,.tgz,.zip,.gz" data-file-input>
|
||||
<div class="file-dropzone-content">
|
||||
<span class="material-symbols-outlined">upload_file</span>
|
||||
<strong>Kéo version mới vào đây hoặc chọn file</strong>
|
||||
<small>File .deb hoặc archive Docker export đều dùng được</small>
|
||||
<button class="btn btn-secondary" type="button" data-file-browse>
|
||||
<span class="material-symbols-outlined">attach_file</span>
|
||||
Chọn file
|
||||
</button>
|
||||
</div>
|
||||
<div class="file-preview" data-file-preview hidden>
|
||||
<span class="material-symbols-outlined">draft</span>
|
||||
<div>
|
||||
<strong data-file-name>Chưa chọn file</strong>
|
||||
<small data-file-meta></small>
|
||||
</div>
|
||||
<button class="icon-button subtle" type="button" title="Bỏ file" aria-label="Bỏ file đã chọn" data-file-clear>
|
||||
<span class="material-symbols-outlined">close</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<label class="form-field full">
|
||||
<span>Docker image/tag</span>
|
||||
<input type="text" name="dockerImage" placeholder="registry.local/robot/fleet-agent:2.0.0">
|
||||
</label>
|
||||
<label class="form-field full">
|
||||
<span>Change log</span>
|
||||
<textarea name="changeLog" placeholder="Mô tả thay đổi trong version này"></textarea>
|
||||
</label>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button class="btn btn-secondary" type="button" data-modal-close>Hủy</button>
|
||||
<button class="btn btn-primary" type="submit">Cập nhật</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user