feat: List of Online Devices

This commit is contained in:
Gustavo Carreiro 2026-02-16 09:18:24 -03:00
parent fa3e49bce1
commit 6ec6fa55df
4 changed files with 101 additions and 6 deletions

View file

@ -16,8 +16,16 @@ export interface SyncthingFolder {
paused?: boolean;
}
export interface SyncthingDevice {
deviceID: string;
name: string;
address: string[];
paused: boolean;
}
export interface SyncthingConfig {
folders: SyncthingFolder[];
devices: SyncthingDevice[];
}
export interface SyncthingFolderStats {
@ -136,6 +144,18 @@ export class SyncthingAPI {
return config.folders;
}
static async getDevices(
url: string,
apiKey: string,
): Promise<SyncthingDevice[]> {
const config = await this.request<SyncthingConfig>(
url,
apiKey,
"/rest/config",
);
return config.devices;
}
// --- Folder Operations ---
static async getFolderStats(

View file

@ -42,6 +42,8 @@ export default class SyncthingController extends Plugin {
public connectedDevices: number = 0;
public currentStatus: SyncStatus = "desconhecido";
public isPaused: boolean = false;
public deviceMap: Map<string, string> = new Map();
public connectedDeviceNames: string[] = [];
get apiUrl(): string {
const protocol = this.settings.useHttps ? "https://" : "http://";
@ -487,17 +489,48 @@ export default class SyncthingController extends Plugin {
}
}
async fetchDeviceMap() {
try {
const devices = await SyncthingAPI.getDevices(
this.apiUrl,
this.settings.syncthingApiKey,
);
this.deviceMap.clear();
devices.forEach((device) => {
// Use label/name if available, otherwise fallback to ID
const name = device.name || device.deviceID.substring(0, 7);
this.deviceMap.set(device.deviceID, name);
});
} catch (e) {
Logger.error(
LOG_MODULES.MAIN,
"Erro ao buscar mapa de dispositivos",
e,
);
}
}
async atualizarContagemDispositivos() {
try {
// Ensure map is populated/updated
if (this.deviceMap.size === 0) {
await this.fetchDeviceMap();
}
const connections = await SyncthingAPI.getConnections(
this.apiUrl,
this.settings.syncthingApiKey,
);
const devices = connections.connections || {};
const count = Object.values(devices).filter(
(d: { connected: boolean }) => d.connected,
).length;
this.connectedDevices = count;
const connectedIDs = Object.keys(devices).filter(
(id) => devices[id].connected,
);
this.connectedDevices = connectedIDs.length;
this.connectedDeviceNames = connectedIDs.map((id) => {
return this.deviceMap.get(id) || id.substring(0, 7);
});
this.atualizarTodosVisuais();
} catch {
// Fail silently

View file

@ -117,12 +117,35 @@ export class SyncthingView extends ItemView {
t("info_last_sync"),
this.plugin.lastSyncTime,
);
// 3.1 Devices Row (Badges)
this.createRow(
infoContainer,
"monitor",
t("info_devices"),
this.plugin.connectedDevices.toString(),
"", // Value empty, we will append badges
);
// Get the last row's value container to append badges
const rows = infoContainer.querySelectorAll(".st-info-row");
const lastRow = rows[rows.length - 1];
const valueDiv = lastRow.querySelector(".st-info-value");
if (valueDiv) {
valueDiv.empty(); // Clear text
// Ensure flex wrap for multiple badges
valueDiv.addClass("st-badges-container");
const deviceNames = this.plugin.connectedDeviceNames;
if (deviceNames.length === 0) {
valueDiv.setText("0");
} else {
deviceNames.forEach((name) => {
valueDiv.createSpan({
cls: "st-device-badge",
text: name,
});
});
}
}
const folderDisplay =
this.plugin.settings.syncthingFolderLabel || "Default";

View file

@ -257,7 +257,7 @@
}
.st-history-container {
max-height: 200px;
max-height: 50vh;
overflow-y: auto;
border: 1px solid var(--background-modifier-border);
border-radius: 4px;
@ -472,3 +472,22 @@
color: var(--text-success) !important;
opacity: 1 !important;
}
/* --- Badges de Dispositivos --- */
.st-badges-container {
display: flex;
flex-wrap: wrap;
gap: 4px;
justify-content: flex-end; /* Alinha badges à direita */
max-width: 60%; /* Evita ocupar toda a linha se o label for longo */
}
.st-device-badge {
font-size: 0.75em;
background-color: var(--background-modifier-border);
color: var(--text-normal);
padding: 2px 6px;
border-radius: 4px;
border: 1px solid var(--background-modifier-border-hover);
white-space: nowrap;
}