Compare commits

...

17 Commits

Author SHA1 Message Date
Manuel
dfcb899013 Stale time for entity state (#1702) 2023-11-23 22:21:34 +01:00
Manuel
5522abdfb6 🔖 Increase version (#1699) 2023-11-23 21:46:51 +01:00
Manuel
312e2c8297 #698 homeassistant widget (#1658) 2023-11-23 21:44:05 +01:00
Thomas Camlong
7f46fafbb9 🌐 New Crowdin updates (#1692) 2023-11-23 21:43:18 +01:00
Tagaishi
5a8a378a2e 🐛 Affix overlapping custom CSS box (#1687) 2023-11-21 18:34:01 +01:00
Thomas Camlong
fe63c03372 🌐 New Crowdin updates (#1682) 2023-11-21 18:33:18 +01:00
Meier Lukas
eadfa4a10f Add support for installation in address bar (#1675) 2023-11-18 22:11:29 +01:00
Thomas Camlong
5aefd0962f New Crowdin updates (#1641) 2023-11-18 15:43:46 +01:00
tuxsudo
da7c111438 Allow custom nextauth port (#1663) 2023-11-18 15:42:47 +01:00
Thomas Camlong
228c51299b Merge pull request #1651 from ajnart/fix-notebook-settings-overlapped 2023-11-15 20:54:40 +01:00
Thomas Camlong
57975f3030 Merge pull request #1652 from ajnart/fix-edit-mode-notification-link
🐛 Link to definition of screen sized for edit mode notification wrong
2023-11-15 09:08:57 +01:00
Thomas Camlong
f4e737b4a1 Merge pull request #1654 from ajnart/add-licence-field-to-migration-package-json
🐛 Migrate package.json has no license field
2023-11-15 09:08:26 +01:00
Tagaishi
a933406ef8 Merge pull request #1655 from No-Maines-Land/patch-1
Update GeneralTab.tsx
2023-11-15 08:40:46 +01:00
No-Maines-Land
a30d6f6f7b Update GeneralTab.tsx 2023-11-15 01:03:38 -05:00
Meier Lukas
34074b1c92 🐛 Migrate package.json has no license field 2023-11-15 06:48:23 +01:00
Meier Lukas
f7ab929bcb 🐛 Link to definition of screen sized for edit mode notification wrong 2023-11-15 06:44:07 +01:00
Meier Lukas
21dcde44a1 🐛 Notebook edit button placed above edit mode settings 2023-11-15 06:39:40 +01:00
67 changed files with 466 additions and 157 deletions

View File

@@ -1,4 +1,5 @@
{ {
"license": "MIT",
"description": "This package.json is used for the migration script the dependencies are only installed within the Dockerfile.", "description": "This package.json is used for the migration script the dependencies are only installed within the Dockerfile.",
"scripts": { "scripts": {
"db:migrate": "ts-node ./migrate.ts" "db:migrate": "ts-node ./migrate.ts"

View File

@@ -1,6 +1,6 @@
{ {
"name": "homarr", "name": "homarr",
"version": "0.14.1", "version": "0.14.2",
"description": "Homarr - A homepage for your server.", "description": "Homarr - A homepage for your server.",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
@@ -233,4 +233,4 @@
] ]
} }
} }
} }

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "宽度", "width": "宽度",
"height": "高度" "height": "高度"
} },
"public": "公开",
"restricted": "限制"
} }

View File

@@ -5,7 +5,7 @@
"key": "快捷键", "key": "快捷键",
"action": "操作", "action": "操作",
"keybinds": "热键绑定", "keybinds": "热键绑定",
"translators": "翻译 ({{count}})", "translators": "翻译 ({{count}})",
"translatorsDescription": "感谢这些人Homarr 现已支持 {{languages}} 种语言!想要帮助将 Homarr 翻译成您的语言吗?请阅读<a>此处</a>了解如何执行此操作 。", "translatorsDescription": "感谢这些人Homarr 现已支持 {{languages}} 种语言!想要帮助将 Homarr 翻译成您的语言吗?请阅读<a>此处</a>了解如何执行此操作 。",
"contributors": "贡献者 ({{count}})", "contributors": "贡献者 ({{count}})",
"contributorsDescription": "这些人构建了让 homarr 工作的代码!想帮助建造 Homarr 吗?请阅读<a>此处</a>了解如何操作", "contributorsDescription": "这些人构建了让 homarr 工作的代码!想帮助建造 Homarr 吗?请阅读<a>此处</a>了解如何操作",

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "crwdns3910:0crwdne3910:0", "width": "crwdns3910:0crwdne3910:0",
"height": "crwdns3912:0crwdne3912:0" "height": "crwdns3912:0crwdne3912:0"
} },
"public": "crwdns4034:0crwdne4034:0",
"restricted": "crwdns4036:0crwdne4036:0"
} }

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "", "width": "",
"height": "" "height": ""
} },
"public": "",
"restricted": ""
} }

View File

@@ -36,7 +36,7 @@
"footer": { "footer": {
"error": "", "error": "",
"lastUpdated": "Naposledy aktualizováno před {{time}}", "lastUpdated": "Naposledy aktualizováno před {{time}}",
"ratioGlobal": "Globální poměr", "ratioGlobal": "Obecný poměr",
"ratioWithFilter": "Filtrovaný poměr" "ratioWithFilter": "Filtrovaný poměr"
}, },
"table": { "table": {

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "Bredde", "width": "Bredde",
"height": "Højde" "height": "Højde"
} },
"public": "Offentlig",
"restricted": "Begrænset"
} }

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "Breite", "width": "Breite",
"height": "Höhe" "height": "Höhe"
} },
"public": "Öffentlich sichtbar",
"restricted": "Eingeschränkt"
} }

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "Πλάτος", "width": "Πλάτος",
"height": "Ύψος" "height": "Ύψος"
} },
"public": "Δημόσιο",
"restricted": "Περιορισμένη πρόσβαση"
} }

View File

@@ -0,0 +1,17 @@
{
"entityNotFound": "Entity not found",
"descriptor": {
"name": "Home Assistant entity",
"description": "Current state of an entity in Home Assistant",
"settings": {
"title": "Entity state",
"entityId": {
"label": "Entity ID",
"info": "Unique entity ID in Home Assistant. Copy by clicking on entity > Click on cog icon > Click on copy button at 'Entity ID'. Some custom entities may not be supported."
},
"displayName": {
"label": "Display name"
}
}
}
}

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "Ancho", "width": "Ancho",
"height": "Alto" "height": "Alto"
} },
"public": "Pública",
"restricted": "Restringido"
} }

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "Largeur", "width": "Largeur",
"height": "Hauteur" "height": "Hauteur"
} },
"public": "Public",
"restricted": "Restreint"
} }

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "רוחב", "width": "רוחב",
"height": "גובה" "height": "גובה"
} },
"public": "ציבורי",
"restricted": "מוגבל"
} }

View File

@@ -19,26 +19,26 @@
"label": "רקע" "label": "רקע"
}, },
"backgroundImageAttachment": { "backgroundImageAttachment": {
"label": "", "label": "צירוף תמונת רקע",
"options": { "options": {
"fixed": "", "fixed": "קבוע - הרקע נשאר באותו מיקום (מומלץ)",
"scroll": "" "scroll": "גלילה - גלילה ברקע עם העכבר"
} }
}, },
"backgroundImageSize": { "backgroundImageSize": {
"label": "", "label": "גודל תמונת רקע",
"options": { "options": {
"cover": "", "cover": "כיסוי - קנה מידה קטן ככל האפשר של התמונה כדי לכסות את כל החלון על ידי חיתוך שטח מוגזם. (מוּמלָץ)",
"contain": "" "contain": "מכיל - קנה מידה גדול ככל האפשר של התמונה בתוך המיכל שלה מבלי לחתוך או למתוח את התמונה."
} }
}, },
"backgroundImageRepeat": { "backgroundImageRepeat": {
"label": "", "label": "צירוף תמונת רקע",
"options": { "options": {
"repeat": "", "repeat": "חזור - התמונה חוזרת על עצמה ככל שנדרש כדי לכסות את כל אזור ציור תמונת הרקע.",
"no-repeat": "", "no-repeat": "ללא חזרה - התמונה אינה חוזרת על עצמה וייתכן שלא תמלא את כל החלל (מומלץ)",
"repeat-x": "", "repeat-x": "חזור X - זהה ל'חזרה' אבל רק על הציר האופקי.",
"repeat-y": "" "repeat-y": "חזור Y - זהה ל'חזרה' אבל רק על הציר האנכי."
} }
}, },
"customCSS": { "customCSS": {

View File

@@ -2,7 +2,7 @@
"title": "דוקר", "title": "דוקר",
"alerts": { "alerts": {
"notConfigured": { "notConfigured": {
"text": "" "text": "למופע ה-Homarr שלך לא הוגדר Docker או שהוא נכשל באחזור קונטיינרים. אנא עיין בתיעוד כיצד להגדיר את האינטגרציה."
} }
}, },
"modals": { "modals": {

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "Širina", "width": "Širina",
"height": "Visina" "height": "Visina"
} },
"public": "Javno",
"restricted": ""
} }

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "Szélesség", "width": "Szélesség",
"height": "Magasság" "height": "Magasság"
} },
"public": "Nyilvános",
"restricted": "Korlátozott"
} }

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "Larghezza", "width": "Larghezza",
"height": "Altezza" "height": "Altezza"
} },
"public": "Pubblico",
"restricted": "Limitato"
} }

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "幅", "width": "幅",
"height": "高さ" "height": "高さ"
} },
"public": "公開",
"restricted": ""
} }

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "너비", "width": "너비",
"height": "높이" "height": "높이"
} },
"public": "공개",
"restricted": ""
} }

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "Platums", "width": "Platums",
"height": "Augstums" "height": "Augstums"
} },
"public": "Publisks",
"restricted": ""
} }

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "Breedte", "width": "Breedte",
"height": "Hoogte" "height": "Hoogte"
} },
"public": "Openbaar",
"restricted": ""
} }

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "Bredde", "width": "Bredde",
"height": "Høyde" "height": "Høyde"
} },
"public": "Offentlig",
"restricted": ""
} }

View File

@@ -1,7 +1,7 @@
{ {
"save": "Zapisz", "save": "Zapisz",
"apply": "Zastosuj", "apply": "Zastosuj",
"insert": "", "insert": "Wstaw",
"about": "O programie", "about": "O programie",
"cancel": "Anuluj", "cancel": "Anuluj",
"close": "Zamknij", "close": "Zamknij",
@@ -45,11 +45,13 @@
"seeMore": "Zobacz więcej...", "seeMore": "Zobacz więcej...",
"position": { "position": {
"left": "Lewo", "left": "Lewo",
"center": "", "center": "Wyśrodkowany",
"right": "Prawo" "right": "Prawo"
}, },
"attributes": { "attributes": {
"width": "Szerokość", "width": "Szerokość",
"height": "Wysokość" "height": "Wysokość"
} },
"public": "Publiczna",
"restricted": "Ograniczone"
} }

View File

@@ -20,11 +20,11 @@
"lines": { "lines": {
"nothingAfterPort": "W większości, jeśli nie we wszystkich przypadkach, nie należy wprowadzać żadnej ścieżki po porcie. (Nawet '/admin' dla pihole lub '/web' dla plex)", "nothingAfterPort": "W większości, jeśli nie we wszystkich przypadkach, nie należy wprowadzać żadnej ścieżki po porcie. (Nawet '/admin' dla pihole lub '/web' dla plex)",
"protocolCheck": "Zawsze upewnij się, że adres URL jest poprzedzony przez http lub https, i upewnij się, że używasz odpowiedniego adresu.", "protocolCheck": "Zawsze upewnij się, że adres URL jest poprzedzony przez http lub https, i upewnij się, że używasz odpowiedniego adresu.",
"preferIP": "", "preferIP": "Zalecane jest użycie bezpośredniego adresu IP maszyny lub kontenera, z którym próbujesz się komunikować.",
"enablePings": "", "enablePings": "Sprawdź, czy adres IP jest prawidłowy, włączając polecenia ping. Dostosuj tablicę -> Układ -> Włącz pingi. Na kafelkach aplikacji pojawi się mała czerwona lub zielona dymka, a najechanie na nią spowoduje wyświetlenie kodu odpowiedzi (w większości przypadków oczekiwana jest zielona dymka z kodem 200).",
"wget": "", "wget": "Aby mieć pewność, że homarr będzie mógł komunikować się z innymi aplikacjami, wykonaj wget/curl/ping IP:port aplikacji.",
"iframe": "", "iframe": "Jeśli chodzi o ramki iframe, powinny one zawsze używać tego samego protokołu (http/s), co Homarr.",
"clearCache": "" "clearCache": "Niektóre informacje są rejestrowane w pamięci podręcznej, więc integracja może nie działać, jeśli nie wyczyścisz pamięci podręcznej w ogólnych opcjach Homarr."
}, },
"footer": "Aby uzyskać więcej informacji na temat rozwiązywania problemów, skontaktuj się z nami na naszym {{discord}}." "footer": "Aby uzyskać więcej informacji na temat rozwiązywania problemów, skontaktuj się z nami na naszym {{discord}}."
} }

View File

@@ -3,7 +3,7 @@
"name": "Kalendarz", "name": "Kalendarz",
"description": "Wyświetla kalendarz z nadchodzącymi wydaniami, z obsługiwanych integracji.", "description": "Wyświetla kalendarz z nadchodzącymi wydaniami, z obsługiwanych integracji.",
"settings": { "settings": {
"title": "Ustawienia dla widżetu Kalendarz", "title": "Ustawienia dla widżetu Kalendarza",
"radarrReleaseType": { "radarrReleaseType": {
"label": "Rodzaj premiery w Radarr", "label": "Rodzaj premiery w Radarr",
"data": { "data": {

View File

@@ -1,6 +1,6 @@
{ {
"descriptor": { "descriptor": {
"name": "Dash.", "name": "Dach.",
"description": "Wyświetla wykresy zewnętrznego Dash. Instancja wewnątrz Homarr.", "description": "Wyświetla wykresy zewnętrznego Dash. Instancja wewnątrz Homarr.",
"settings": { "settings": {
"title": "Ustawienia dla widgetu Dash.", "title": "Ustawienia dla widgetu Dash.",
@@ -82,7 +82,7 @@
} }
}, },
"card": { "card": {
"title": "Dash.", "title": "Dach.",
"errors": { "errors": {
"noService": "Nie znaleziono usługi Dash. Proszę dodać ją do pulpitu Homarra lub ustawić adres URL usługi Dash. w opcjach modułu", "noService": "Nie znaleziono usługi Dash. Proszę dodać ją do pulpitu Homarra lub ustawić adres URL usługi Dash. w opcjach modułu",
"noInformation": "Nie można uzyskać informacji z dash. - używasz najnowszej wersji?", "noInformation": "Nie można uzyskać informacji z dash. - używasz najnowszej wersji?",

View File

@@ -8,7 +8,7 @@
"label": "Pokaż pasek narzędzi ułatwiający pisanie w markdown" "label": "Pokaż pasek narzędzi ułatwiający pisanie w markdown"
}, },
"allowReadOnlyCheck": { "allowReadOnlyCheck": {
"label": "" "label": "Zezwalaj na sprawdzanie w trybie tylko do odczytu"
}, },
"content": { "content": {
"label": "Zawartość notatnika" "label": "Zawartość notatnika"
@@ -39,7 +39,7 @@
"image": "Osadź obraz", "image": "Osadź obraz",
"addTable": "Dodaj tabelę", "addTable": "Dodaj tabelę",
"deleteTable": "Usuń tabelę", "deleteTable": "Usuń tabelę",
"colorCell": "", "colorCell": "Kolor Komórki",
"mergeCell": "Przełączanie scalania komórek", "mergeCell": "Przełączanie scalania komórek",
"addColumnLeft": "Dodaj kolumnę przed", "addColumnLeft": "Dodaj kolumnę przed",
"addColumnRight": "Dodaj kolumnę po", "addColumnRight": "Dodaj kolumnę po",

View File

@@ -11,10 +11,10 @@
"label": "Wyświetlanie ukończonych torrentów" "label": "Wyświetlanie ukończonych torrentów"
}, },
"displayActiveTorrents": { "displayActiveTorrents": {
"label": "" "label": "Wyświetl aktywne torrenty"
}, },
"speedLimitOfActiveTorrents": { "speedLimitOfActiveTorrents": {
"label": "" "label": "Prędkość wysyłania pozwalająca uznać torrent za aktywny (kB/s)"
}, },
"displayStaleTorrents": { "displayStaleTorrents": {
"label": "Wyświetlanie nieaktualnych torrentów" "label": "Wyświetlanie nieaktualnych torrentów"

View File

@@ -19,26 +19,26 @@
"label": "Tło" "label": "Tło"
}, },
"backgroundImageAttachment": { "backgroundImageAttachment": {
"label": "", "label": "Ustawienie obrazu tła",
"options": { "options": {
"fixed": "", "fixed": "Fixed Tło pozostaje w tej samej pozycji (zalecane)",
"scroll": "" "scroll": "Scroll - Tło przewija się za pomocą myszy"
} }
}, },
"backgroundImageSize": { "backgroundImageSize": {
"label": "", "label": "Rozmiar obrazu tła",
"options": { "options": {
"cover": "", "cover": "Cover — skaluje obraz do najmniejszego możliwego rozmiaru, aby pokryć całe okno poprzez przycięcie nadmiernej przestrzeni. (Zalecana)",
"contain": "" "contain": "Contain — skaluje obraz do największego możliwego rozmiaru w jego kontenerze, bez przycinania i rozciągania obrazu."
} }
}, },
"backgroundImageRepeat": { "backgroundImageRepeat": {
"label": "", "label": "Ustawienie obrazu tła",
"options": { "options": {
"repeat": "", "repeat": "Repeat — obraz jest powtarzany tak często, jak to konieczne, aby pokryć cały obszar obrazu tła.",
"no-repeat": "", "no-repeat": "No repeat — obraz nie jest powtarzany i może nie wypełniać całej przestrzeni (zalecane)",
"repeat-x": "", "repeat-x": "Repeat X — to samo co „Powtórz”, ale tylko na osi poziomej.",
"repeat-y": "" "repeat-y": "Repeat Y — to samo co „Powtórz”, ale tylko w osi pionowej."
} }
}, },
"customCSS": { "customCSS": {

View File

@@ -2,7 +2,7 @@
"title": "Docker", "title": "Docker",
"alerts": { "alerts": {
"notConfigured": { "notConfigured": {
"text": "" "text": "Twoja instancja Homarr nie ma skonfigurowanego Dockera lub nie była w stanie pobrać listę kontenerów. Sprawdź dokumentację, aby dowiedzieć się, jak skonfigurować integrację."
} }
}, },
"modals": { "modals": {

View File

@@ -1,7 +1,7 @@
{ {
"save": "Salvar", "save": "Salvar",
"apply": "", "apply": "Aplicar",
"insert": "", "insert": "Inserir",
"about": "Sobre", "about": "Sobre",
"cancel": "Cancelar", "cancel": "Cancelar",
"close": "Fechar", "close": "Fechar",
@@ -45,11 +45,13 @@
"seeMore": "Veja mais...", "seeMore": "Veja mais...",
"position": { "position": {
"left": "Esquerda", "left": "Esquerda",
"center": "", "center": "Centralizado",
"right": "Certo" "right": "Certo"
}, },
"attributes": { "attributes": {
"width": "Largura", "width": "Largura",
"height": "Altura" "height": "Altura"
} },
"public": "Público",
"restricted": "Restrito"
} }

View File

@@ -5,10 +5,10 @@
"key": "Tecla de atalho", "key": "Tecla de atalho",
"action": "Ação", "action": "Ação",
"keybinds": "Ligações de teclas", "keybinds": "Ligações de teclas",
"translators": "", "translators": "Tradutores ({{count}})",
"translatorsDescription": "", "translatorsDescription": "Graças a essas pessoas, o Homarr está disponível em {{languages}} idiomas! Quer ajudar a traduzir o Homarr para seu idioma? Veja como fazer isso <a>aqui</a>.",
"contributors": "", "contributors": "Colaboradores ({{count}})",
"contributorsDescription": "", "contributorsDescription": "Essas pessoas criaram o código que faz o homarr funcionar! Quer ajudar a construir o Homarr? Veja como fazer isso <a>aqui</a>",
"actions": { "actions": {
"toggleTheme": "Alternar o modo claro/escuro", "toggleTheme": "Alternar o modo claro/escuro",
"focusSearchBar": "Foco na barra de pesquisa", "focusSearchBar": "Foco na barra de pesquisa",

View File

@@ -21,8 +21,8 @@
"metrics": { "metrics": {
"domainsOnAdlist": "Domínios em adlists", "domainsOnAdlist": "Domínios em adlists",
"queriesToday": "Consultas hoje", "queriesToday": "Consultas hoje",
"queriesBlockedTodayPercentage": "", "queriesBlockedTodayPercentage": "Bloqueado hoje",
"queriesBlockedToday": "" "queriesBlockedToday": "Bloqueado hoje"
} }
} }
} }

View File

@@ -8,7 +8,7 @@
"label": "Mostrar a barra de ferramentas para ajudá-lo a escrever markdown" "label": "Mostrar a barra de ferramentas para ajudá-lo a escrever markdown"
}, },
"allowReadOnlyCheck": { "allowReadOnlyCheck": {
"label": "" "label": "Permitir a verificação no modo de leitura"
}, },
"content": { "content": {
"label": "O conteúdo do notebook" "label": "O conteúdo do notebook"
@@ -17,43 +17,43 @@
}, },
"card": { "card": {
"controls": { "controls": {
"bold": "", "bold": "Negrito",
"italic": "", "italic": "Itálico",
"strikethrough": "", "strikethrough": "Riscar",
"underline": "", "underline": "Sublinhar",
"colorText": "", "colorText": "Cor do texto",
"colorHighlight": "", "colorHighlight": "Texto colorido em destaque",
"code": "", "code": "Código",
"clear": "", "clear": "Limpar formatação",
"heading": "", "heading": "Cabeçalho {{level}}",
"align": "", "align": "Alinhar texto: {{position}}",
"blockquote": "", "blockquote": "Bloco de Citação",
"horizontalLine": "", "horizontalLine": "Linha horizontal",
"bulletList": "", "bulletList": "Lista de marcadores",
"orderedList": "", "orderedList": "Lista ordenada",
"checkList": "", "checkList": "Lista de verificação",
"increaseIndent": "", "increaseIndent": "Aumentar recuo",
"decreaseIndent": "", "decreaseIndent": "Diminuir recuo",
"link": "", "link": "Link",
"unlink": "", "unlink": "Remover link",
"image": "", "image": "Incorporar imagem",
"addTable": "", "addTable": "Adicionar tabela",
"deleteTable": "", "deleteTable": "Excluir tabela",
"colorCell": "", "colorCell": "Cor da Célula",
"mergeCell": "", "mergeCell": "Ativar/desativar mesclagem de células",
"addColumnLeft": "", "addColumnLeft": "Adicionar coluna antes",
"addColumnRight": "", "addColumnRight": "Adicionar coluna depois",
"deleteColumn": "", "deleteColumn": "Excluir coluna",
"addRowTop": "", "addRowTop": "Adicionar linha antes",
"addRowBelow": "", "addRowBelow": "Adicionar linha depois",
"deleteRow": "" "deleteRow": "Excluir linha"
}, },
"modals": { "modals": {
"clearColor": "", "clearColor": "Limpar cor",
"source": "", "source": "Fonte",
"widthPlaceholder": "", "widthPlaceholder": "Valor em % ou pixels",
"columns": "", "columns": "Colunas",
"rows": "" "rows": "Linhas"
} }
} }
} }

View File

@@ -11,10 +11,10 @@
"label": "Mostrar torrentes completas" "label": "Mostrar torrentes completas"
}, },
"displayActiveTorrents": { "displayActiveTorrents": {
"label": "" "label": "Exibir torrents ativos"
}, },
"speedLimitOfActiveTorrents": { "speedLimitOfActiveTorrents": {
"label": "" "label": "Velocidade de upload para considerar um torrent como ativo (kB/s)"
}, },
"displayStaleTorrents": { "displayStaleTorrents": {
"label": "Exibição de torrentes envelhecidas" "label": "Exibição de torrentes envelhecidas"
@@ -27,8 +27,8 @@
"description": "Quando a opção \"is whitelist\" estiver marcada, ela funcionará como uma lista de permissões. Se não estiver marcada, será uma lista negra. Não fará nada quando estiver vazia" "description": "Quando a opção \"is whitelist\" estiver marcada, ela funcionará como uma lista de permissões. Se não estiver marcada, será uma lista negra. Não fará nada quando estiver vazia"
}, },
"displayRatioWithFilter": { "displayRatioWithFilter": {
"label": "", "label": "Exibir proporção da lista de torrents filtrados",
"info": "" "info": "Se estiver desativado, somente a proporção global será exibida. A proporção global ainda usará os rótulos se estiver definida"
} }
} }
}, },
@@ -36,8 +36,8 @@
"footer": { "footer": {
"error": "Erro", "error": "Erro",
"lastUpdated": "Última actualização {{time}} atrás", "lastUpdated": "Última actualização {{time}} atrás",
"ratioGlobal": "", "ratioGlobal": "Proporção global",
"ratioWithFilter": "" "ratioWithFilter": "Proporção com filtro"
}, },
"table": { "table": {
"header": { "header": {

View File

@@ -22,7 +22,7 @@
"description": "Configure o Homarr para usuários com deficiência ou incapacitados" "description": "Configure o Homarr para usuários com deficiência ou incapacitados"
}, },
"access": { "access": {
"name": "", "name": "Acesso",
"description": "Configure quem tem acesso ao seu quadro" "description": "Configure quem tem acesso ao seu quadro"
} }
} }

View File

@@ -19,26 +19,26 @@
"label": "Antecedentes" "label": "Antecedentes"
}, },
"backgroundImageAttachment": { "backgroundImageAttachment": {
"label": "", "label": "Anexo de imagem de fundo",
"options": { "options": {
"fixed": "", "fixed": "Fixado - O plano de fundo permanece na mesma posição (recomendado)",
"scroll": "" "scroll": "Rolagem - O plano de fundo rola com seu mouse"
} }
}, },
"backgroundImageSize": { "backgroundImageSize": {
"label": "", "label": "Tamanho da imagem de fundo",
"options": { "options": {
"cover": "", "cover": "Capa - Dimensiona a imagem o menor possível para cobrir toda a janela cortando o espaço excessivo. (recomendado)",
"contain": "" "contain": "Conter - Dimensiona a imagem o máximo possível dentro de seu contêiner, sem cortar ou esticar a imagem."
} }
}, },
"backgroundImageRepeat": { "backgroundImageRepeat": {
"label": "", "label": "Anexo de imagem de fundo",
"options": { "options": {
"repeat": "", "repeat": "Repetir - A imagem é repetida o quanto for necessário para cobrir toda a área de pintura da imagem de fundo.",
"no-repeat": "", "no-repeat": "Sem repetição - A imagem não se repete e pode não preencher todo o espaço (recomendado)",
"repeat-x": "", "repeat-x": "Repetir X - O mesmo que 'Repetir', mas apenas no eixo horizontal.",
"repeat-y": "" "repeat-y": "Repetir Y - O mesmo que 'Repetir', mas apenas no eixo vertical."
} }
}, },
"customCSS": { "customCSS": {

View File

@@ -2,16 +2,16 @@
"title": "Docker", "title": "Docker",
"alerts": { "alerts": {
"notConfigured": { "notConfigured": {
"text": "" "text": "Sua instância do Homarr não possui o Docker configurado ou falhou em buscar contêineres. Por favor, verifique a documentação sobre como configurar a integração."
} }
}, },
"modals": { "modals": {
"selectBoard": { "selectBoard": {
"title": "Escolha uma placa", "title": "Escolha um quadro",
"text": "Escolha o quadro em que deseja adicionar os aplicativos para os contêineres do Docker selecionados.", "text": "Escolha o quadro em que deseja adicionar os aplicativos para os contêineres do Docker selecionados.",
"form": { "form": {
"board": { "board": {
"label": "Diretoria" "label": "Quadro"
}, },
"submit": "Adicionar aplicativos" "submit": "Adicionar aplicativos"
} }

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "Ширина", "width": "Ширина",
"height": "Высота" "height": "Высота"
} },
"public": "Публичный",
"restricted": ""
} }

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "Šírka", "width": "Šírka",
"height": "Výška" "height": "Výška"
} },
"public": "Verejné",
"restricted": ""
} }

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "Širina", "width": "Širina",
"height": "Višina" "height": "Višina"
} },
"public": "Javna stran",
"restricted": ""
} }

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "Bredd", "width": "Bredd",
"height": "Höjd" "height": "Höjd"
} },
"public": "Publik",
"restricted": ""
} }

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "Genişlik", "width": "Genişlik",
"height": "Yükseklik" "height": "Yükseklik"
} },
"public": "Herkese açık",
"restricted": "Sınırlı"
} }

View File

@@ -21,7 +21,7 @@
"backgroundImageAttachment": { "backgroundImageAttachment": {
"label": "Arkaplan resim ekle", "label": "Arkaplan resim ekle",
"options": { "options": {
"fixed": "Düzeltildi - Arka plan aynı konumda kalıyor (tavsiye edilen)", "fixed": "Sabit - Arka plan aynı konumda kalır (önerilir)",
"scroll": "Kaydırma - Arka plan farenizle kaydırılır" "scroll": "Kaydırma - Arka plan farenizle kaydırılır"
} }
}, },
@@ -36,7 +36,7 @@
"label": "Arkaplan resim ekle", "label": "Arkaplan resim ekle",
"options": { "options": {
"repeat": "Tekrarla - Resim, arka plan görüntü alanının tamamını kapsayacak şekilde gerektiği kadar tekrarlanır.", "repeat": "Tekrarla - Resim, arka plan görüntü alanının tamamını kapsayacak şekilde gerektiği kadar tekrarlanır.",
"no-repeat": "", "no-repeat": "Tekrarsız - Resim tekrarlanmaz ve tüm alanı doldurmayabilir (önerilir)",
"repeat-x": "Tekrarla X - 'Tekrarla' ile aynıdır ancak yalnızca yatay eksende.", "repeat-x": "Tekrarla X - 'Tekrarla' ile aynıdır ancak yalnızca yatay eksende.",
"repeat-y": "Tekrar Y - 'Tekrarla' ile aynıdır, ancak yalnızca dikey eksende." "repeat-y": "Tekrar Y - 'Tekrarla' ile aynıdır, ancak yalnızca dikey eksende."
} }

View File

@@ -1,3 +1,3 @@
{ {
"label": "Gölge" "label": "Gölge "
} }

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "寬度", "width": "寬度",
"height": "高度" "height": "高度"
} },
"public": "公開",
"restricted": "受到限制"
} }

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "Ширина", "width": "Ширина",
"height": "Висота" "height": "Висота"
} },
"public": "Публічний",
"restricted": ""
} }

View File

@@ -51,5 +51,7 @@
"attributes": { "attributes": {
"width": "Chiều rộng", "width": "Chiều rộng",
"height": "Chiều cao" "height": "Chiều cao"
} },
"public": "Công khai",
"restricted": ""
} }

View File

@@ -1,4 +1,6 @@
{ {
"name": "Homarr",
"start_url": "/",
"display": "standalone", "display": "standalone",
"icons": [ "icons": [
{ {

View File

@@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
echo "Exporting hostname..." echo "Exporting hostname..."
export NEXTAUTH_URL_INTERNAL="http://$HOSTNAME:7575" export NEXTAUTH_URL_INTERNAL="http://$HOSTNAME:${PORT:-7575}"
echo "Migrating database..." echo "Migrating database..."
cd ./migrate; yarn db:migrate & PID=$! cd ./migrate; yarn db:migrate & PID=$!

View File

@@ -24,7 +24,6 @@ export const GeneralTab = ({ form, openTab }: GeneralTabProps) => {
t('general.internalAddress.troubleshoot.lines.enablePings'), t('general.internalAddress.troubleshoot.lines.enablePings'),
t('general.internalAddress.troubleshoot.lines.wget'), t('general.internalAddress.troubleshoot.lines.wget'),
t('general.internalAddress.troubleshoot.lines.iframe'), t('general.internalAddress.troubleshoot.lines.iframe'),
t('general.internalAddress.troubleshoot.lines.clearCache'),
]; ];
return ( return (

View File

@@ -183,4 +183,9 @@ export const availableIntegrations = [
image: 'https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/adguard-home.png', image: 'https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/adguard-home.png',
label: 'AdGuard Home', label: 'AdGuard Home',
}, },
{
value: 'homeAssistant',
image: 'https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/home-assistant.png',
label: 'Home Assistant'
}
] as const satisfies Readonly<SelectItem[]>; ] as const satisfies Readonly<SelectItem[]>;

View File

@@ -2,17 +2,13 @@ import { Button, Global, Text, Title, Tooltip, clsx } from '@mantine/core';
import { useHotkeys, useWindowEvent } from '@mantine/hooks'; import { useHotkeys, useWindowEvent } from '@mantine/hooks';
import { openContextModal } from '@mantine/modals'; import { openContextModal } from '@mantine/modals';
import { hideNotification, showNotification } from '@mantine/notifications'; import { hideNotification, showNotification } from '@mantine/notifications';
import { import { IconApps, IconEditCircle, IconEditCircleOff, IconSettings } from '@tabler/icons-react';
IconApps,
IconEditCircle,
IconEditCircleOff,
IconSettings
} from '@tabler/icons-react';
import Consola from 'consola'; import Consola from 'consola';
import { useSession } from 'next-auth/react'; import { useSession } from 'next-auth/react';
import { Trans, useTranslation } from 'next-i18next'; import { Trans, useTranslation } from 'next-i18next';
import Link from 'next/link'; import Link from 'next/link';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { env } from 'process';
import { useEditModeStore } from '~/components/Dashboard/Views/useEditModeStore'; import { useEditModeStore } from '~/components/Dashboard/Views/useEditModeStore';
import { useNamedWrapperColumnCount } from '~/components/Dashboard/Wrappers/gridstack/store'; import { useNamedWrapperColumnCount } from '~/components/Dashboard/Wrappers/gridstack/store';
import { BoardHeadOverride } from '~/components/layout/Meta/BoardHeadOverride'; import { BoardHeadOverride } from '~/components/layout/Meta/BoardHeadOverride';
@@ -20,7 +16,6 @@ import { HeaderActionButton } from '~/components/layout/header/ActionButton';
import { useConfigContext } from '~/config/provider'; import { useConfigContext } from '~/config/provider';
import { api } from '~/utils/api'; import { api } from '~/utils/api';
import { env } from 'process';
import { MainLayout } from './MainLayout'; import { MainLayout } from './MainLayout';
type BoardLayoutProps = { type BoardLayoutProps = {
@@ -32,10 +27,7 @@ export const BoardLayout = ({ children }: BoardLayoutProps) => {
const { data: session } = useSession(); const { data: session } = useSession();
return ( return (
<MainLayout <MainLayout autoFocusSearch={session?.user.autoFocusSearch} headerActions={<HeaderActions />}>
autoFocusSearch={session?.user.autoFocusSearch}
headerActions={<HeaderActions />}
>
<BoardHeadOverride /> <BoardHeadOverride />
<BackgroundImage /> <BackgroundImage />
{children} {children}
@@ -135,7 +127,7 @@ const ToggleEditModeButton = () => {
<Text <Text
component="a" component="a"
style={{ color: 'inherit', textDecoration: 'underline' }} style={{ color: 'inherit', textDecoration: 'underline' }}
href="https://homarr.dev/docs/customizations/layout" href="https://homarr.dev/docs/customizations/board-customization#screen-sizes"
target="_blank" target="_blank"
/> />
), ),
@@ -205,7 +197,7 @@ const BackgroundImage = () => {
backgroundPosition: 'center center', backgroundPosition: 'center center',
backgroundSize: config?.settings.customization.backgroundImageSize ?? 'cover', backgroundSize: config?.settings.customization.backgroundImageSize ?? 'cover',
backgroundRepeat: config?.settings.customization.backgroundImageRepeat ?? 'no-repeat', backgroundRepeat: config?.settings.customization.backgroundImageRepeat ?? 'no-repeat',
backgroundAttachment: config?.settings.customization.backgroundImageAttachment ?? 'fixed' backgroundAttachment: config?.settings.customization.backgroundImageAttachment ?? 'fixed',
}, },
}} }}
/> />

View File

@@ -229,7 +229,7 @@ export default function CustomizationPage({
)} )}
</Transition> </Transition>
</Affix> </Affix>
<Container> <Container pb="6rem">
<Paper p="xl" py="sm" mih="100%" withBorder> <Paper p="xl" py="sm" mih="100%" withBorder>
<Stack> <Stack>
<Group position="apart"> <Group position="apart">

View File

@@ -1,5 +1,4 @@
import { createTRPCRouter } from '~/server/api/trpc'; import { createTRPCRouter } from '~/server/api/trpc';
import { appRouter } from './routers/app'; import { appRouter } from './routers/app';
import { boardRouter } from './routers/board'; import { boardRouter } from './routers/board';
import { calendarRouter } from './routers/calendar'; import { calendarRouter } from './routers/calendar';
@@ -16,6 +15,7 @@ import { notebookRouter } from './routers/notebook';
import { overseerrRouter } from './routers/overseerr'; import { overseerrRouter } from './routers/overseerr';
import { passwordRouter } from './routers/password'; import { passwordRouter } from './routers/password';
import { rssRouter } from './routers/rss'; import { rssRouter } from './routers/rss';
import { smartHomeEntityStateRouter } from './routers/smart-home/entity-state';
import { timezoneRouter } from './routers/timezone'; import { timezoneRouter } from './routers/timezone';
import { usenetRouter } from './routers/usenet/router'; import { usenetRouter } from './routers/usenet/router';
import { userRouter } from './routers/user'; import { userRouter } from './routers/user';
@@ -47,6 +47,7 @@ export const rootRouter = createTRPCRouter({
boards: boardRouter, boards: boardRouter,
password: passwordRouter, password: passwordRouter,
notebook: notebookRouter, notebook: notebookRouter,
smartHomeEntityState: smartHomeEntityStateRouter
}); });
// export type definition of API // export type definition of API

View File

@@ -0,0 +1,53 @@
import { TRPCError } from '@trpc/server';
import { ZodError, z } from 'zod';
import { createTRPCRouter, protectedProcedure } from '../../trpc';
import { findAppProperty } from '~/tools/client/app-properties';
import { getConfig } from '~/tools/config/getConfig';
import { HomeAssistantSingleton } from '~/tools/singleton/HomeAssistantSingleton';
export const smartHomeEntityStateRouter = createTRPCRouter({
retrieveStatus: protectedProcedure
.input(
z.object({
configName: z.string(),
entityId: z.string().regex(/^[A-Za-z0-9-_\.]+$/)
})
)
.query(async ({ input }) => {
const config = getConfig(input.configName);
const instances = config.apps.filter((app) => app.integration?.type == 'homeAssistant');
for (var instance of instances) {
const url = new URL(instance.url);
const client = HomeAssistantSingleton.getOrSet(url, findAppProperty(instance, 'apiKey'));
const state = await client.getEntityState(input.entityId);
if (!state.success) {
if (!(state.error instanceof ZodError)) {
continue;
}
// Consola.error('Unable to handle entity state: ', state.error);
throw new TRPCError({
code: 'NOT_IMPLEMENTED',
message: `Unable to handle Home Assistant entity state. This may be due to malformed response or unknown entity type. Check log for details`
});
}
if(!state.data) {
throw new TRPCError({
code: 'INTERNAL_SERVER_ERROR',
message: `Home Assistant: Unable to connect to app '${instance.id}'. Check logs for details`
});
}
return state.data;
}
return null;
}),
});

View File

@@ -0,0 +1,41 @@
import Consola from 'consola';
import { appendPath } from '~/tools/shared/strings';
import { entityStateSchema } from './models/EntityState';
export class HomeAssistant {
public readonly basePath: URL;
private readonly token: string;
constructor(url: URL, token: string) {
if (!url.pathname.endsWith('/')) {
url.pathname += "/";
}
url.pathname += 'api';
this.basePath = url;
this.token = token;
}
async getEntityState(entityId: string) {
try {
const response = await fetch(appendPath(this.basePath, `/states/${entityId}`), {
headers: {
'Authorization': `Bearer ${this.token}`
}
});
const body = await response.json();
if (!response.ok) {
return {
success: false as const,
error: body
};
}
return entityStateSchema.safeParseAsync(body);
} catch (err) {
Consola.error(`Failed to fetch from '${this.basePath}': ${err}`);
return {
success: false as const,
error: err
};
}
}
}

View File

@@ -0,0 +1,12 @@
import { z } from 'zod';
export const entityStateSchema = z.object({
attributes: z.record(z.union([z.string(), z.number(), z.boolean()])),
entity_id: z.string(),
last_changed: z.string().pipe(z.coerce.date()),
last_updated: z.string().pipe(z.coerce.date()),
state: z.string(),
});
export type EntityState = z.infer<typeof entityStateSchema>;

View File

@@ -29,6 +29,7 @@ export const boardNamespaces = [
'modules/dns-hole-controls', 'modules/dns-hole-controls',
'modules/bookmark', 'modules/bookmark',
'modules/notebook', 'modules/notebook',
'modules/smart-home/entity-state',
'widgets/error-boundary', 'widgets/error-boundary',
'widgets/draggable-list', 'widgets/draggable-list',
'widgets/location', 'widgets/location',

View File

@@ -12,3 +12,9 @@ export const trimStringEnding = (original: string, toTrimIfExists: string[]) =>
export const firstUpperCase = (str: string) => { export const firstUpperCase = (str: string) => {
return str.charAt(0).toUpperCase() + str.slice(1); return str.charAt(0).toUpperCase() + str.slice(1);
}; };
export const appendPath = (url: URL, path: string) => {
const newUrl = new URL(url);
newUrl.pathname += path;
return newUrl;
}

View File

@@ -0,0 +1,20 @@
import { HomeAssistant } from '../server/sdk/homeassistant/HomeAssistant';
export class HomeAssistantSingleton {
private static _instances: HomeAssistant[] = [];
public static getOrSet(url: URL, token: string): HomeAssistant {
const match = this._instances.find(
(instance) =>
instance.basePath.hostname === url.hostname && instance.basePath.port === url.port
);
if (!match) {
const instance = new HomeAssistant(url, token);
this._instances.push(instance);
return instance;
}
return match;
}
}

View File

@@ -1,4 +1,5 @@
import { Icon, IconKey, IconPassword, IconUser } from '@tabler/icons-react'; import { Icon, IconKey, IconPassword, IconUser } from '@tabler/icons-react';
import { Property } from 'csstype'; import { Property } from 'csstype';
import { TileBaseType } from './tile'; import { TileBaseType } from './tile';
@@ -55,7 +56,8 @@ export type IntegrationType =
| 'jellyfin' | 'jellyfin'
| 'nzbGet' | 'nzbGet'
| 'pihole' | 'pihole'
| 'adGuardHome'; | 'adGuardHome'
| 'homeAssistant';
export type AppIntegrationType = { export type AppIntegrationType = {
type: IntegrationType | null; type: IntegrationType | null;
@@ -97,6 +99,7 @@ export const integrationFieldProperties: {
plex: ['apiKey'], plex: ['apiKey'],
pihole: ['apiKey'], pihole: ['apiKey'],
adGuardHome: ['username', 'password'], adGuardHome: ['username', 'password'],
homeAssistant: ['apiKey']
}; };
export type IntegrationFieldDefinitionType = { export type IntegrationFieldDefinitionType = {

View File

@@ -11,6 +11,7 @@ import mediaRequestsStats from './media-requests/MediaRequestStatsTile';
import mediaServer from './media-server/MediaServerTile'; import mediaServer from './media-server/MediaServerTile';
import notebook from './notebook/NotebookWidgetTile'; import notebook from './notebook/NotebookWidgetTile';
import rss from './rss/RssWidgetTile'; import rss from './rss/RssWidgetTile';
import smartHomeEntityState from './smart-home/entity-state/entity-state.widget';
import torrent from './torrent/TorrentTile'; import torrent from './torrent/TorrentTile';
import usenet from './useNet/UseNetTile'; import usenet from './useNet/UseNetTile';
import videoStream from './video/VideoStreamTile'; import videoStream from './video/VideoStreamTile';
@@ -34,4 +35,5 @@ export default {
'dns-hole-controls': dnsHoleControls, 'dns-hole-controls': dnsHoleControls,
bookmark, bookmark,
notebook, notebook,
'smart-home/entity-state': smartHomeEntityState
}; };

View File

@@ -52,6 +52,7 @@ import StarterKit from '@tiptap/starter-kit';
import { useSession } from 'next-auth/react'; import { useSession } from 'next-auth/react';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { Dispatch, SetStateAction, useState } from 'react'; import { Dispatch, SetStateAction, useState } from 'react';
import { useEditModeStore } from '~/components/Dashboard/Views/useEditModeStore';
import { useConfigContext } from '~/config/provider'; import { useConfigContext } from '~/config/provider';
import { useConfigStore } from '~/config/store'; import { useConfigStore } from '~/config/store';
import { api } from '~/utils/api'; import { api } from '~/utils/api';
@@ -62,9 +63,10 @@ import { INotebookWidget } from './NotebookWidgetTile';
export function Editor({ widget }: { widget: INotebookWidget }) { export function Editor({ widget }: { widget: INotebookWidget }) {
const [content, setContent] = useState(widget.properties.content); const [content, setContent] = useState(widget.properties.content);
const [toSaveContent, setToSaveContent] = useState(content); const [toSaveContent, setToSaveContent] = useState(content);
const isEditMode = useEditModeStore((x) => x.enabled);
const { data: sessionData } = useSession(); const { data: sessionData } = useSession();
const enabled = !!sessionData?.user.isAdmin; const enabled = !!sessionData?.user.isAdmin && !isEditMode;
const [isEditing, setIsEditing] = useState(false); const [isEditing, setIsEditing] = useState(false);
const { config, name: configName } = useConfigContext(); const { config, name: configName } = useConfigContext();

View File

@@ -0,0 +1,98 @@
import { Center, Loader, Stack, Text, Tooltip } from '@mantine/core';
import { IconAlertHexagon, IconBinaryTree, IconExclamationMark } from '@tabler/icons-react';
import { useTranslation } from 'react-i18next';
import { useConfigContext } from '~/config/provider';
import { api } from '~/utils/api';
import { defineWidget } from '~/widgets/helper';
import { WidgetLoading } from '~/widgets/loading';
import { IWidget } from '~/widgets/widgets';
const definition = defineWidget({
id: 'smart-home/entity-state',
icon: IconBinaryTree,
options: {
entityId: {
type: 'text',
defaultValue: 'sun.sun',
info: true,
},
displayName: {
type: 'text',
defaultValue: 'Sun',
},
},
gridstack: {
minWidth: 1,
minHeight: 1,
maxWidth: 12,
maxHeight: 12,
},
component: EntityStateTile,
});
export type ISmartHomeEntityStateWidget = IWidget<(typeof definition)['id'], typeof definition>;
interface SmartHomeEntityStateWidgetProps {
widget: ISmartHomeEntityStateWidget;
}
function EntityStateTile({ widget }: SmartHomeEntityStateWidgetProps) {
const { t } = useTranslation('modules/smart-home/entity-state');
const { name: configName } = useConfigContext();
const { data, isInitialLoading, isLoading, isError, error } =
api.smartHomeEntityState.retrieveStatus.useQuery(
{
configName: configName!,
entityId: widget.properties.entityId,
},
{
enabled: !!configName,
refetchInterval: 2 * 60 * 1000
}
);
let dataComponent = null;
if (isError) {
dataComponent = (
<Tooltip label={error.message} withArrow withinPortal>
<IconAlertHexagon color="red" />
</Tooltip>
);
}
if (!dataComponent && isInitialLoading) {
dataComponent = <WidgetLoading />;
}
if (!dataComponent && !data) {
dataComponent = (
<Tooltip label={t('entityNotFound')} withArrow withinPortal>
<IconExclamationMark color="red" />
</Tooltip>
);
}
if (!dataComponent) {
dataComponent = (
<Text align="center">
{data?.state}
{isLoading && <Loader ml="xs" size={10} />}
</Text>
);
}
return (
<Center h="100%" w="100%">
<Stack align="center" spacing={3}>
<Text align="center" weight="bold" size="lg">
{widget.properties.displayName}
</Text>
{dataComponent}
</Stack>
</Center>
);
}
export default definition;