Skip to content
15 changes: 15 additions & 0 deletions docs/customservices.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ within Homer:
- [rTorrent](#rtorrent)
- [SABnzbd](#sabnzbd)
- [Scrutiny](#scrutiny)
- [SFTPGo](#sftpgo)
- [Speedtest Tracker](#speedtesttracker)
- [Tautulli](#tautulli)
- [Tdarr](#tdarr)
Expand Down Expand Up @@ -646,6 +647,20 @@ This service displays info about the total number of disk passed and failed S.M.
updateInterval: 5000 # (Optional) Interval (in ms) for updating the status
```

## SFTPGo

This service displays a version string instead of a subtitle.
And this service display the number of active connections is hidden on small screen.
The indicator shows SFTPGo is online, offline. Example configuration:

```yaml
- name: "SFTPGO container"
type: "SFTPGo"
logo: assets/tools/sample.png
url: http://sftp-go.example.com
sftpgo_api_key: "hYdn26pTteWZNzbAXoiqgR.jG7TKwtoMRAMrJAGgdr3Ha"
```

## SpeedtestTracker

This service will show the download and upload speeds in Mbit/s and the ping in ms.
Expand Down
22 changes: 22 additions & 0 deletions dummy-data/sftpgo/api/v2/connections
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[
{
"username": "test",
"connection_id": "SFTP_94f5b2b9f379173fa9cd0b8a836a7f40d860e4299e167793722d1e957a94e4d2_1",
"client_version": "SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.13",
"remote_address": "192.168.1.15:37616",
"connection_time": 1751462552179,
"last_activity": 1751462552179,
"current_time": 1751462680531,
"protocol": "SFTP"
},
{
"username": "test",
"connection_id": "SFTP_f50a640bded5f2dda3f9861b0f73c1d9220fe65da1de1bbb5c549618221a6455_1",
"client_version": "SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.13",
"remote_address": "192.168.1.15:37680",
"connection_time": 1751462590652,
"last_activity": 1751462590652,
"current_time": 1751462680531,
"protocol": "SFTP"
}
]
17 changes: 17 additions & 0 deletions dummy-data/sftpgo/api/v2/version
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"version": "2.6.6",
"build_date": "2025-02-24T18:47:26Z",
"commit_hash": "6825db76",
"features": [
"+metrics",
"+azblob",
"+gcs",
"+s3",
"+bolt",
"+mysql",
"+pgsql",
"+sqlite",
"+unixcrypt",
"+portable"
]
}
107 changes: 107 additions & 0 deletions src/components/services/Sftpgo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<template>
<Generic :item="item">
<template #content>
<p class="title is-4">{{ item.name }}</p>
<p class="subtitle is-6">
<template v-if="item.subtitle">
{{ item.subtitle }}
</template>
<template v-else>
<span v-if="versionstring">Version {{ versionstring }}</span>
<span v-if="activeConnections !== null && !this.showUpdateAvailable">
– Active connections: {{ activeConnections }}
Comment on lines +11 to +12
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea here is to not show the line on small screen right? why showUpdateAvailable is named like that ? It's not related to updates ? or I'm missing something ?
You may be able to reduce the message (for example, just {{ activeConnections }} connections or {{ activeConnections }} clients) to make it fit on most screen and avoid the need to have a matchMedia check.

</span>
</template>
</p>
</template>
<template #indicator>
<div v-if="status" class="status" :class="status">
{{ status }}
</div>
</template>
</Generic>
</template>

<script>
import service from "@/mixins/service.js";

export default {
name: "SFTPGo",
mixins: [service],
props: {
item: Object,
},
data: () => ({
fetchOk: null,
versionstring: null,
activeConnections: null,
}),
computed: {
status: function () {
return this.fetchOk ? "online" : "offline";
},
showUpdateAvailable: function () {
return this.isSmallScreenMethod();
},
},
created() {
this.fetchStatus();
},
methods: {
isSmallScreenMethod: function () {
return window.matchMedia("screen and (max-width: 1023px)").matches;
},
fetchStatus: async function () {
let headers = {};
if (this.item.sftpgo_api_key) {
headers["X-SFTPGO-API-KEY"] = `${this.item.sftpgo_api_key}`;
}
try {
const [versionRes, connRes] = await Promise.all([
this.fetch("/api/v2/version", { headers }),
this.fetch("/api/v2/connections", { headers }),
]);

this.versionstring = versionRes.version || "unknown";
this.activeConnections = connRes.length;

this.fetchOk = true;
} catch (e) {
console.error(e);
this.fetchOk = false;
}
},
},
};
</script>

<style scoped lang="scss">
.status {
font-size: 0.8rem;
color: var(--text-title);
white-space: nowrap;
margin-left: 0.25rem;

&.online:before {
background-color: #94e185;
border-color: #78d965;
box-shadow: 0 0 5px 1px #94e185;
}

&.offline:before {
background-color: #c9404d;
border-color: #c42c3b;
box-shadow: 0 0 5px 1px #c9404d;
}

&:before {
content: " ";
display: inline-block;
width: 7px;
height: 7px;
margin-right: 10px;
border: 1px solid #000;
border-radius: 7px;
}
}
</style>