create-openclaw-bot 5.13.5 → 5.13.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*Run one command → open the dashboard → your bot is live. Windows · macOS · Linux · VPS — Docker-powered, auto-installed for you.*
|
|
8
8
|
|
|
9
9
|
<p align="center">
|
|
10
|
-
<a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.13.
|
|
10
|
+
<a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.13.8-0EA5E9?style=for-the-badge" alt="Version 5.13.8" /></a>
|
|
11
11
|
<a href="https://github.com/tuanminhhole/openclaw-setup?tab=MIT-1-ov-file"><img src="https://img.shields.io/badge/LICENSE-MIT-success?style=for-the-badge" alt="MIT License" /></a>
|
|
12
12
|
<a href="https://www.npmjs.com/package/create-openclaw-bot"><img src="https://img.shields.io/npm/v/create-openclaw-bot?style=for-the-badge&label=CLI&color=2563EB&logo=npm&logoColor=white" alt="NPM Version" /></a>
|
|
13
13
|
<a href="https://github.com/tuanminhhole/openclaw-setup/stargazers"><img src="https://img.shields.io/github/stars/tuanminhhole/openclaw-setup?style=for-the-badge&color=eab308&logo=github&logoColor=white" alt="GitHub Stars" /></a>
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
|
|
38
38
|
---
|
|
39
39
|
|
|
40
|
-
## 🆕 What's New in v5.13.
|
|
40
|
+
## 🆕 What's New in v5.13.8
|
|
41
41
|
|
|
42
42
|
- ⚙️ **New Settings page**: pick your theme (light/dark toggle), language (VI/EN) and timezone right from the dashboard — available in both the sidebar and the mobile nav bar.
|
|
43
43
|
- 🕒 **Schedules & cron run in the correct local time**: newly created bots carry an explicit timezone, so reminders/cron no longer drift a day off around midnight (a UTC-vs-local bug that could schedule into the past). Scheduling guidance was hardened end-to-end (local time + timezone, explicit delivery target, raw group id).
|
package/README.vi.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*Chạy một lệnh → mở dashboard → bot lên sóng. Windows · macOS · Linux · VPS — chạy trên Docker, tự cài giúp bạn.*
|
|
8
8
|
|
|
9
9
|
<p align="center">
|
|
10
|
-
<a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.13.
|
|
10
|
+
<a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.13.8-0EA5E9?style=for-the-badge" alt="Version 5.13.8" /></a>
|
|
11
11
|
<a href="https://github.com/tuanminhhole/openclaw-setup?tab=MIT-1-ov-file"><img src="https://img.shields.io/badge/LICENSE-MIT-success?style=for-the-badge" alt="MIT License" /></a>
|
|
12
12
|
<a href="https://www.npmjs.com/package/create-openclaw-bot"><img src="https://img.shields.io/npm/v/create-openclaw-bot?style=for-the-badge&label=CLI&color=2563EB&logo=npm&logoColor=white" alt="NPM Version" /></a>
|
|
13
13
|
<a href="https://github.com/tuanminhhole/openclaw-setup/stargazers"><img src="https://img.shields.io/github/stars/tuanminhhole/openclaw-setup?style=for-the-badge&color=eab308&logo=github&logoColor=white" alt="GitHub Stars" /></a>
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
|
|
38
38
|
---
|
|
39
39
|
|
|
40
|
-
## 🆕 Có gì mới trong v5.13.
|
|
40
|
+
## 🆕 Có gì mới trong v5.13.8
|
|
41
41
|
|
|
42
42
|
- ⚙️ **Trang Cài đặt mới**: chọn giao diện (nút gạt Sáng/Tối), ngôn ngữ (VI/EN) và múi giờ ngay trong dashboard — có ở cả sidebar lẫn thanh điều hướng mobile.
|
|
43
43
|
- 🕒 **Lịch & cron chạy đúng giờ địa phương**: bot tạo mới nhận múi giờ rõ ràng, nên nhắc hẹn/cron không còn lệch 1 ngày quanh nửa đêm (lỗi UTC-vs-local có thể đặt lịch vào quá khứ). Đã siết hướng dẫn lập lịch toàn diện (giờ local + múi giờ, nơi gửi rõ ràng, ID nhóm dạng thô).
|
|
@@ -1465,12 +1465,19 @@ async function createBotInProject(projectDir, body = {}, runtime = {}) {
|
|
|
1465
1465
|
cfg.bindings.push({ agentId, match: { channel: 'telegram', accountId } });
|
|
1466
1466
|
await appendEnvValue(projectDir, accountId === 'default' ? 'TELEGRAM_BOT_TOKEN' : `TELEGRAM_BOT_TOKEN_${agentId.toUpperCase().replace(/[^A-Z0-9]+/g, '_')}`, token);
|
|
1467
1467
|
} else if (channel === 'zalo-personal') {
|
|
1468
|
-
const existingZaloConnectBindings = cfg.bindings.filter((b) => b.match?.channel === 'zalo-connect').length;
|
|
1469
|
-
if (existingZaloConnectBindings > 0) {
|
|
1470
|
-
throw httpError(400, 'OpenClaw Zalo Connect hiện hỗ trợ 1 tài khoản Zalo mỗi project. Hãy dùng bot Zalo hiện có hoặc tạo project riêng cho tài khoản thứ hai.');
|
|
1471
|
-
}
|
|
1472
1468
|
ensureZaloConnectChannel(cfg);
|
|
1473
|
-
|
|
1469
|
+
// zalo-connect (fork ≥3.0) is genuinely multi-account: API clients, stored
|
|
1470
|
+
// credentials and QR login are all keyed by accountId. So multiple Zalo
|
|
1471
|
+
// numbers can coexist in one project (mirrors Telegram): the first Zalo bot
|
|
1472
|
+
// uses 'default', each additional one gets its own account keyed by agentId.
|
|
1473
|
+
// Each new account still needs its own QR login (startZaloLogin reads the
|
|
1474
|
+
// accountId from this binding).
|
|
1475
|
+
const existingZaloConnectBindings = cfg.bindings.filter((b) => b.match?.channel === 'zalo-connect').length;
|
|
1476
|
+
accountId = existingZaloConnectBindings === 0 ? 'default' : agentId;
|
|
1477
|
+
const zc = cfg.channels['zalo-connect'];
|
|
1478
|
+
zc.accounts = zc.accounts || {};
|
|
1479
|
+
zc.accounts[accountId] = zc.accounts[accountId] || { enabled: true };
|
|
1480
|
+
zc.defaultAccount = zc.defaultAccount || 'default';
|
|
1474
1481
|
cfg.bindings.push({ agentId, match: { channel: 'zalo-connect', accountId } });
|
|
1475
1482
|
} else if (channel === 'fb-messenger') {
|
|
1476
1483
|
// Token handling (user token → permanent Page token) is done by the fb-messenger
|
|
@@ -1754,10 +1761,8 @@ async function startZaloConnectLogin(projectDir, accountId = 'default') {
|
|
|
1754
1761
|
if (!gatewayReady) {
|
|
1755
1762
|
const check = await runCapture('docker', ['exec', botContainer, 'sh', '-lc', '[ -d "${OPENCLAW_HOME:-/home/node/project/.openclaw}/extensions/zalo-connect" ] && echo OK || echo MISSING'], { cwd: projectDir, shell: false }).catch(() => ({ stdout: 'ERR' }));
|
|
1756
1763
|
if (String(check.stdout || '').trim() === 'MISSING') {
|
|
1757
|
-
sendLog(`[zalo-connect] Plugin missing — installing
|
|
1758
|
-
const
|
|
1759
|
-
const ref = String(ZALO_CONNECT_PLUGIN_SPEC).split('#')[1] || ZALO_CONNECT_VERSION;
|
|
1760
|
-
const installCmd = `tmp=/tmp/openclaw-plugin-zalo-connect-${ref}; rm -rf "$tmp"; git clone --depth 1 --branch "${ref}" "${repo}" "$tmp" && rm -rf "$tmp/.git" && cd /home/node/project && openclaw plugins install "$tmp" 2>&1`;
|
|
1764
|
+
sendLog(`[zalo-connect] Plugin missing — installing ${ZALO_CONNECT_PLUGIN_SPEC}...`);
|
|
1765
|
+
const installCmd = `cd /home/node/project && openclaw plugins install ${ZALO_CONNECT_PLUGIN_SPEC} --force --acknowledge-clawhub-risk 2>&1`;
|
|
1761
1766
|
const inst = await runCapture('docker', ['exec', botContainer, 'sh', '-lc', installCmd], { cwd: projectDir, shell: false });
|
|
1762
1767
|
const instOut = `${inst.stdout}\n${inst.stderr}`;
|
|
1763
1768
|
for (const line of instOut.split(/\r?\n/).filter(Boolean)) sendLog(`[zalo-connect] ${line}`);
|
|
@@ -3343,19 +3348,17 @@ async function installFeature(projectDir, agentId, kind, id) {
|
|
|
3343
3348
|
}
|
|
3344
3349
|
|
|
3345
3350
|
if (kind === 'plugin') {
|
|
3346
|
-
// zalo-connect
|
|
3347
|
-
//
|
|
3348
|
-
//
|
|
3351
|
+
// zalo-connect ships on ClawHub (package `openclaw-zalo-connect`) — install/update via
|
|
3352
|
+
// clawhub:latest like other plugins, so the dashboard "Update" button always fetches the newest
|
|
3353
|
+
// published version (no tag pin to bump each release).
|
|
3349
3354
|
if (id === 'zalo-connect' || id === 'openclaw-zalo-connect') {
|
|
3350
3355
|
let composeDir = null;
|
|
3351
3356
|
if (existsSync(join(projectDir, 'docker-compose.yml'))) composeDir = projectDir;
|
|
3352
3357
|
else if (existsSync(join(projectDir, 'docker', 'openclaw', 'docker-compose.yml'))) composeDir = join(projectDir, 'docker', 'openclaw');
|
|
3353
|
-
const repo = String(ZALO_CONNECT_PLUGIN_SPEC).split('#')[0];
|
|
3354
|
-
const ref = String(ZALO_CONNECT_PLUGIN_SPEC).split('#')[1] || ZALO_CONNECT_VERSION;
|
|
3355
3358
|
if (composeDir) {
|
|
3356
3359
|
const botContainer = getBotContainerName(projectDir);
|
|
3357
|
-
sendLog(`[zalo-connect] Installing/updating
|
|
3358
|
-
const cmd = `
|
|
3360
|
+
sendLog(`[zalo-connect] Installing/updating ${ZALO_CONNECT_PLUGIN_SPEC} inside ${botContainer}...`);
|
|
3361
|
+
const cmd = `cd /home/node/project && openclaw plugins install ${ZALO_CONNECT_PLUGIN_SPEC} --force --acknowledge-clawhub-risk 2>&1`;
|
|
3359
3362
|
const out = await runCapture('docker', ['exec', botContainer, 'sh', '-lc', cmd], { cwd: projectDir, shell: false });
|
|
3360
3363
|
if (out) for (const line of `${out.stdout}\n${out.stderr}`.split(/\r?\n/).filter(Boolean)) sendLog(`[zalo-connect] ${line}`);
|
|
3361
3364
|
const okDir = existsSync(join(projectDir, '.openclaw', 'extensions', 'zalo-connect'));
|
|
@@ -41,11 +41,13 @@
|
|
|
41
41
|
const TELEGRAM_SETUP_GUIDE_FILENAME = 'TELEGRAM-GROUP-SETUP.md';
|
|
42
42
|
|
|
43
43
|
// ── OpenClaw Zalo Connect — single source of truth ──────────────────────────
|
|
44
|
-
//
|
|
44
|
+
// Installed from ClawHub (owned package `openclaw-zalo-connect`) at LATEST, like zalo-mod, so the
|
|
45
|
+
// dashboard "Update" button + first-boot always fetch the newest published version — no tag pin to
|
|
46
|
+
// bump each release. (Was a pinned git tag; switched once the fork was published to ClawHub.)
|
|
45
47
|
const ZALO_CHANNEL_ID = 'zalo-connect';
|
|
46
48
|
const ZALO_PLUGIN_ID = 'zalo-connect';
|
|
47
|
-
const ZALO_CONNECT_VERSION = '
|
|
48
|
-
const ZALO_CONNECT_PLUGIN_SPEC = '
|
|
49
|
+
const ZALO_CONNECT_VERSION = 'latest';
|
|
50
|
+
const ZALO_CONNECT_PLUGIN_SPEC = 'clawhub:openclaw-zalo-connect';
|
|
49
51
|
|
|
50
52
|
function buildRelayPluginInstallCommand(prefix = 'openclaw') {
|
|
51
53
|
return `if [ ! -d "$OPENCLAW_STATE_DIR/extensions/${TELEGRAM_RELAY_PLUGIN_ID}" ]; then ${prefix} plugins install ${TELEGRAM_RELAY_PLUGIN_SPEC} 2>/dev/null || true; fi`;
|
|
@@ -316,11 +316,11 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
316
316
|
runtimeParts.push(`node - <<'NODE'\n${restoreConfigScript}\nNODE`);
|
|
317
317
|
runtimeParts.push(`node - <<'NODE'\n${securityCompatScript}\nNODE`);
|
|
318
318
|
if (zaloBackend === 'zalo-connect') {
|
|
319
|
-
//
|
|
320
|
-
//
|
|
321
|
-
//
|
|
322
|
-
//
|
|
323
|
-
const zaloConnectSpec = common.ZALO_CONNECT_PLUGIN_SPEC || '
|
|
319
|
+
// ZaloConnect install from ClawHub (latest). ensure_plugin skips when extensions/zalo-connect
|
|
320
|
+
// already exists, so restarts never re-download; the "Update" button in the dashboard fetches
|
|
321
|
+
// newer versions. No dist patching, no mentions.js, no watchdog: sticker/mention/reaction are
|
|
322
|
+
// native ZaloConnect actions.
|
|
323
|
+
const zaloConnectSpec = common.ZALO_CONNECT_PLUGIN_SPEC || 'clawhub:openclaw-zalo-connect';
|
|
324
324
|
runtimeParts.push(`ensure_plugin zalo-connect "${zaloConnectSpec}"`);
|
|
325
325
|
}
|
|
326
326
|
runtimeParts.push('openclaw gateway run');
|
|
@@ -693,8 +693,8 @@ Ngoài gửi text, tool \`${zaloDeliveryChannel}\` có ~149 action. Gọi bằng
|
|
|
693
693
|
// straight from the workspace path; files must be copied into the shared outbound media
|
|
694
694
|
// store first, then sent via the `message` tool. Injected into every AGENTS.md variant.
|
|
695
695
|
const fileSendRule = isVi
|
|
696
|
-
? `\n\n## 📤 Quy tắc xuất & gửi file (Excel, tài liệu, ảnh...)\nDo sandbox bảo mật của OpenClaw (nhất là kênh Zalo cá nhân), khi cần gửi BẤT KỲ file nào cho user:\n1. Tạo/xuất file trong workspace của bạn (vd: \`${workspacePath}/bao-cao.xlsx\`).\n2. Tạo thư mục outbound (nếu chưa có) RỒI copy — chạy đúng 1 lệnh: \`mkdir -p /home/node/project/.openclaw/media/outbound && cp <đường-dẫn-file> /home/node/project/.openclaw/media/outbound/\`. (Bỏ qua \`mkdir -p\` thì copy sẽ lỗi khi thư mục chưa tồn tại. Dùng \`cp\`, KHÔNG dùng \`copy\`.)\n3. Gửi cho user bằng tool \`message\` (action="send") với đường dẫn file trong \`media/outbound/\`.\n- ⚠️ **Định dạng:** dùng định dạng HIỆN ĐẠI (\`.xlsx\`, \`.pdf\`, \`.png\`, \`.jpg\`). TUYỆT ĐỐI tránh \`.xls\` đời cũ. Lý do: OpenClaw chỉ cho gửi file mà loại media/tài liệu **xác thực được từ nội dung** (buffer-verified); \`.xls\` chỉ ra MIME fallback (\`application/vnd.ms-excel\`) nên bị CHẶN — đây là policy của OpenClaw, KHÔNG phải do Zalo/Telegram chặn, và KHÔNG liên quan group hay DM. Xuất Excel thì luôn xuất \`.xlsx\`.\n- KHÔNG gửi thẳng từ đường dẫn workspace (dễ bị sandbox chặn).\n- Đặt tên file rõ ràng (kèm thời gian/tên nhóm) để phân biệt; áp dụng cho cả Zalo lẫn Telegram.`
|
|
697
|
-
: `\n\n## 📤 File export & sending rule (Excel, documents, images...)\nDue to OpenClaw's security sandbox (especially the Zalo personal channel), to send ANY file to the user:\n1. Create/export the file in your workspace (e.g. \`${workspacePath}/report.xlsx\`).\n2. Create the outbound dir (if missing) THEN copy — run as one command: \`mkdir -p /home/node/project/.openclaw/media/outbound && cp <file-path> /home/node/project/.openclaw/media/outbound/\`. (Skipping \`mkdir -p\` makes the copy fail when the dir doesn't exist yet. Use \`cp\`, not \`copy\`.)\n3. Send it to the user via the \`message\` tool (action="send") using the path inside \`media/outbound/\`.\n- ⚠️ **Format:** use MODERN formats (\`.xlsx\`, \`.pdf\`, \`.png\`, \`.jpg\`). NEVER use legacy \`.xls\`. Reason: OpenClaw only allows sending files whose media/document type is **buffer-verified** (sniffed from content); \`.xls\` only yields a fallback MIME (\`application/vnd.ms-excel\`) and is BLOCKED — this is an OpenClaw policy, NOT a Zalo/Telegram limit, and is unrelated to group vs DM. Always export Excel as \`.xlsx\`.\n- DO NOT send directly from the workspace path (the sandbox may block it).\n- Use a clear filename (with timestamp/group name); applies to both Zalo and Telegram.`;
|
|
696
|
+
? `\n\n## 📤 Quy tắc xuất & gửi file (Excel, tài liệu, ảnh...)\nDo sandbox bảo mật của OpenClaw (nhất là kênh Zalo cá nhân), khi cần gửi BẤT KỲ file nào cho user:\n1. Tạo/xuất file trong workspace của bạn (vd: \`${workspacePath}/bao-cao.xlsx\`).\n2. Tạo thư mục outbound (nếu chưa có) RỒI copy — chạy đúng 1 lệnh: \`mkdir -p /home/node/project/.openclaw/media/outbound && cp <đường-dẫn-file> /home/node/project/.openclaw/media/outbound/\`. (Bỏ qua \`mkdir -p\` thì copy sẽ lỗi khi thư mục chưa tồn tại. Dùng \`cp\`, KHÔNG dùng \`copy\`.)\n3. Gửi cho user bằng tool \`message\` (action="send") với đường dẫn file trong \`media/outbound/\`.\n- ⚠️ **Định dạng:** dùng định dạng HIỆN ĐẠI (\`.xlsx\`, \`.pdf\`, \`.png\`, \`.jpg\`). TUYỆT ĐỐI tránh \`.xls\` đời cũ. Lý do: OpenClaw chỉ cho gửi file mà loại media/tài liệu **xác thực được từ nội dung** (buffer-verified); \`.xls\` chỉ ra MIME fallback (\`application/vnd.ms-excel\`) nên bị CHẶN — đây là policy của OpenClaw, KHÔNG phải do Zalo/Telegram chặn, và KHÔNG liên quan group hay DM. Xuất Excel thì luôn xuất \`.xlsx\`.\n- KHÔNG gửi thẳng từ đường dẫn workspace (dễ bị sandbox chặn).\n- Đặt tên file rõ ràng (kèm thời gian/tên nhóm) để phân biệt; áp dụng cho cả Zalo lẫn Telegram.\n- ⛔ **CHỈ dùng \`message\`(action="send") cho FILE hoặc khi CHỦ ĐỘNG nhắn sang thread KHÁC.** Để TRẢ LỜI hội thoại hiện tại (chữ), chỉ cần VIẾT nội dung ra — hệ thống tự gửi ĐÚNG 1 LẦN (kèm mention/quote). TUYỆT ĐỐI KHÔNG gọi \`message\`/\`send\` để trả lời thread hiện tại (kể cả sau khi đã dùng tool như phân tích ảnh) → sẽ bị **GỬI ĐÔI**. Và KHÔNG viết câu trạng thái nội bộ kiểu "Đã xử lý xong…", "Không cần thêm gì nữa", "NO_REPLY" — đó là lộ suy nghĩ; chỉ trả lời đúng nội dung, một lần rồi dừng.`
|
|
697
|
+
: `\n\n## 📤 File export & sending rule (Excel, documents, images...)\nDue to OpenClaw's security sandbox (especially the Zalo personal channel), to send ANY file to the user:\n1. Create/export the file in your workspace (e.g. \`${workspacePath}/report.xlsx\`).\n2. Create the outbound dir (if missing) THEN copy — run as one command: \`mkdir -p /home/node/project/.openclaw/media/outbound && cp <file-path> /home/node/project/.openclaw/media/outbound/\`. (Skipping \`mkdir -p\` makes the copy fail when the dir doesn't exist yet. Use \`cp\`, not \`copy\`.)\n3. Send it to the user via the \`message\` tool (action="send") using the path inside \`media/outbound/\`.\n- ⚠️ **Format:** use MODERN formats (\`.xlsx\`, \`.pdf\`, \`.png\`, \`.jpg\`). NEVER use legacy \`.xls\`. Reason: OpenClaw only allows sending files whose media/document type is **buffer-verified** (sniffed from content); \`.xls\` only yields a fallback MIME (\`application/vnd.ms-excel\`) and is BLOCKED — this is an OpenClaw policy, NOT a Zalo/Telegram limit, and is unrelated to group vs DM. Always export Excel as \`.xlsx\`.\n- DO NOT send directly from the workspace path (the sandbox may block it).\n- Use a clear filename (with timestamp/group name); applies to both Zalo and Telegram.\n- ⛔ **Use \`message\`(action="send") ONLY for files or when PROACTIVELY messaging a DIFFERENT thread.** To REPLY to the current conversation (text), just WRITE your response — the system delivers it exactly ONCE (with mention/quote). NEVER call \`message\`/\`send\` to reply to the current thread (even after using a tool like image analysis) → it causes a **DOUBLE message**. And never emit internal status lines like "Done…", "Nothing more needed", or "NO_REPLY" — that leaks your reasoning; just reply with the content, once, then stop.`;
|
|
698
698
|
const securityRules = includeSecurity ? buildSecurityRules(isVi) : '';
|
|
699
699
|
|
|
700
700
|
// Doc structure mirrors OpenClaw's default AGENTS.md (Session Startup, Memory, Red Lines,
|
package/dist/web/app.js
CHANGED
|
@@ -1096,7 +1096,7 @@ function botSkillsPanel() {
|
|
|
1096
1096
|
let toggleHtml = '';
|
|
1097
1097
|
const secs = [];
|
|
1098
1098
|
if (isInstalled) {
|
|
1099
|
-
toggleHtml = `<label class="feature-switch" title="${locked ? t('Bắt buộc cho bot Zalo — không thể tắt','Required for Zalo bots — cannot be disabled') : ''}"><input type="checkbox" data-feature-toggle="${key}" ${(flags[key] || locked) ? 'checked' : ''} ${(loading || locked) ? 'disabled' : ''}/><span></span></label
|
|
1099
|
+
toggleHtml = `<label class="feature-switch" title="${locked ? t('Bắt buộc cho bot Zalo — không thể tắt','Required for Zalo bots — cannot be disabled') : ''}"${locked ? ' style="opacity:.4;pointer-events:none;cursor:not-allowed;"' : ''}><input type="checkbox" data-feature-toggle="${key}" ${(flags[key] || locked) ? 'checked' : ''} ${(loading || locked) ? 'disabled' : ''}/><span></span></label>`;
|
|
1100
1100
|
if (item.openWebPort) {
|
|
1101
1101
|
secs.push(`<a class="secondary icon-btn2" href="${sameHostUrl('', item.openWebPort)}${item.openWebPath || ''}" target="_blank" rel="noopener" title="${t('Mở dashboard của plugin','Open the plugin dashboard')}" style="padding: 4px 8px; font-size: 11px; height: 28px; border-width: 1px;">${actionIcon('link')}<span>${t('Mở web','Open')}</span></a>`);
|
|
1102
1102
|
}
|