osism 0.20250824.0__tar.gz → 0.20250824.1__tar.gz

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.
Files changed (150) hide show
  1. osism-0.20250824.1/AUTHORS +1 -0
  2. osism-0.20250824.1/ChangeLog +7 -0
  3. {osism-0.20250824.0/osism.egg-info → osism-0.20250824.1}/PKG-INFO +1 -1
  4. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/app/nodes/page.tsx +79 -44
  5. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/lib/types.ts +1 -1
  6. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/openstack.py +14 -13
  7. {osism-0.20250824.0 → osism-0.20250824.1/osism.egg-info}/PKG-INFO +1 -1
  8. osism-0.20250824.1/osism.egg-info/pbr.json +1 -0
  9. osism-0.20250824.0/AUTHORS +0 -1
  10. osism-0.20250824.0/ChangeLog +0 -7
  11. osism-0.20250824.0/osism.egg-info/pbr.json +0 -1
  12. {osism-0.20250824.0 → osism-0.20250824.1}/.flake8 +0 -0
  13. {osism-0.20250824.0 → osism-0.20250824.1}/.github/renovate.json +0 -0
  14. {osism-0.20250824.0 → osism-0.20250824.1}/.github/workflows/publish.yml +0 -0
  15. {osism-0.20250824.0 → osism-0.20250824.1}/.hadolint.yaml +0 -0
  16. {osism-0.20250824.0 → osism-0.20250824.1}/.zuul.yaml +0 -0
  17. {osism-0.20250824.0 → osism-0.20250824.1}/Containerfile +0 -0
  18. {osism-0.20250824.0 → osism-0.20250824.1}/Dockerfile +0 -0
  19. {osism-0.20250824.0 → osism-0.20250824.1}/LICENSE +0 -0
  20. {osism-0.20250824.0 → osism-0.20250824.1}/Pipfile +0 -0
  21. {osism-0.20250824.0 → osism-0.20250824.1}/Pipfile.lock +0 -0
  22. {osism-0.20250824.0 → osism-0.20250824.1}/README.md +0 -0
  23. {osism-0.20250824.0 → osism-0.20250824.1}/files/change.sh +0 -0
  24. {osism-0.20250824.0 → osism-0.20250824.1}/files/cleanup-ansible-collections.sh +0 -0
  25. {osism-0.20250824.0 → osism-0.20250824.1}/files/clustershell/clush.conf +0 -0
  26. {osism-0.20250824.0 → osism-0.20250824.1}/files/clustershell/groups.conf +0 -0
  27. {osism-0.20250824.0 → osism-0.20250824.1}/files/data/SCS-Spec.MandatoryFlavors.verbose.yaml +0 -0
  28. {osism-0.20250824.0 → osism-0.20250824.1}/files/netbox-manager/settings.toml +0 -0
  29. {osism-0.20250824.0 → osism-0.20250824.1}/files/redfishMockupCreate.py +0 -0
  30. {osism-0.20250824.0 → osism-0.20250824.1}/files/run-ansible-console.sh +0 -0
  31. {osism-0.20250824.0 → osism-0.20250824.1}/files/sonic/config_db.json +0 -0
  32. {osism-0.20250824.0 → osism-0.20250824.1}/files/sonic/port_config/Accton-AS4625-54T.ini +0 -0
  33. {osism-0.20250824.0 → osism-0.20250824.1}/files/sonic/port_config/Accton-AS5835-54T.ini +0 -0
  34. {osism-0.20250824.0 → osism-0.20250824.1}/files/sonic/port_config/Accton-AS5835-54X.ini +0 -0
  35. {osism-0.20250824.0 → osism-0.20250824.1}/files/sonic/port_config/Accton-AS7326-56X.ini +0 -0
  36. {osism-0.20250824.0 → osism-0.20250824.1}/files/sonic/port_config/Accton-AS7726-32X.ini +0 -0
  37. {osism-0.20250824.0 → osism-0.20250824.1}/files/sonic/port_config/Accton-AS9716-32D.ini +0 -0
  38. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/.dockerignore +0 -0
  39. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/.gitignore +0 -0
  40. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/Containerfile +0 -0
  41. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/Dockerfile +0 -0
  42. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/app/api/config/route.ts +0 -0
  43. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/app/api/health/route.ts +0 -0
  44. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/app/components/ConnectionStatus.tsx +0 -0
  45. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/app/components/EventsFilters.tsx +0 -0
  46. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/app/components/EventsList.tsx +0 -0
  47. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/app/events/page.tsx +0 -0
  48. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/app/favicon.ico +0 -0
  49. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/app/globals.css +0 -0
  50. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/app/layout.tsx +0 -0
  51. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/app/page.tsx +0 -0
  52. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/app/services/page.tsx +0 -0
  53. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/components.json +0 -0
  54. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/eslint.config.mjs +0 -0
  55. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/lib/api.ts +0 -0
  56. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/lib/hooks/useWebSocket.ts +0 -0
  57. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/lib/utils.ts +0 -0
  58. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/next.config.ts +0 -0
  59. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/package-lock.json +0 -0
  60. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/package.json +0 -0
  61. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/postcss.config.mjs +0 -0
  62. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/public/file.svg +0 -0
  63. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/public/globe.svg +0 -0
  64. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/public/next.svg +0 -0
  65. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/public/vercel.svg +0 -0
  66. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/public/window.svg +0 -0
  67. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/tailwind.config.ts +0 -0
  68. {osism-0.20250824.0 → osism-0.20250824.1}/frontend/tsconfig.json +0 -0
  69. {osism-0.20250824.0 → osism-0.20250824.1}/osism/__init__.py +0 -0
  70. {osism-0.20250824.0 → osism-0.20250824.1}/osism/__main__.py +0 -0
  71. {osism-0.20250824.0 → osism-0.20250824.1}/osism/api.py +0 -0
  72. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/__init__.py +0 -0
  73. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/apply.py +0 -0
  74. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/baremetal.py +0 -0
  75. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/compose.py +0 -0
  76. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/compute.py +0 -0
  77. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/configuration.py +0 -0
  78. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/console.py +0 -0
  79. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/container.py +0 -0
  80. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/get.py +0 -0
  81. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/log.py +0 -0
  82. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/manage.py +0 -0
  83. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/netbox.py +0 -0
  84. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/noset.py +0 -0
  85. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/reconciler.py +0 -0
  86. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/redfish.py +0 -0
  87. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/server.py +0 -0
  88. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/service.py +0 -0
  89. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/set.py +0 -0
  90. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/sonic.py +0 -0
  91. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/status.py +0 -0
  92. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/sync.py +0 -0
  93. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/task.py +0 -0
  94. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/validate.py +0 -0
  95. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/vault.py +0 -0
  96. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/volume.py +0 -0
  97. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/wait.py +0 -0
  98. {osism-0.20250824.0 → osism-0.20250824.1}/osism/commands/worker.py +0 -0
  99. {osism-0.20250824.0 → osism-0.20250824.1}/osism/data/__init__.py +0 -0
  100. {osism-0.20250824.0 → osism-0.20250824.1}/osism/data/enums.py +0 -0
  101. {osism-0.20250824.0 → osism-0.20250824.1}/osism/data/playbooks.py +0 -0
  102. {osism-0.20250824.0 → osism-0.20250824.1}/osism/main.py +0 -0
  103. {osism-0.20250824.0 → osism-0.20250824.1}/osism/services/__init__.py +0 -0
  104. {osism-0.20250824.0 → osism-0.20250824.1}/osism/services/event_bridge.py +0 -0
  105. {osism-0.20250824.0 → osism-0.20250824.1}/osism/services/listener.py +0 -0
  106. {osism-0.20250824.0 → osism-0.20250824.1}/osism/services/websocket_manager.py +0 -0
  107. {osism-0.20250824.0 → osism-0.20250824.1}/osism/settings.py +0 -0
  108. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/__init__.py +0 -0
  109. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/ansible.py +0 -0
  110. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/ceph.py +0 -0
  111. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/conductor/__init__.py +0 -0
  112. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/conductor/config.py +0 -0
  113. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/conductor/ironic.py +0 -0
  114. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/conductor/netbox.py +0 -0
  115. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/conductor/redfish.py +0 -0
  116. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/conductor/sonic/__init__.py +0 -0
  117. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/conductor/sonic/bgp.py +0 -0
  118. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/conductor/sonic/cache.py +0 -0
  119. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/conductor/sonic/config_generator.py +0 -0
  120. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/conductor/sonic/connections.py +0 -0
  121. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/conductor/sonic/constants.py +0 -0
  122. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/conductor/sonic/device.py +0 -0
  123. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/conductor/sonic/exporter.py +0 -0
  124. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/conductor/sonic/interface.py +0 -0
  125. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/conductor/sonic/sync.py +0 -0
  126. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/conductor/utils.py +0 -0
  127. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/conductor.py +0 -0
  128. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/kolla.py +0 -0
  129. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/kubernetes.py +0 -0
  130. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/netbox.py +0 -0
  131. {osism-0.20250824.0 → osism-0.20250824.1}/osism/tasks/reconciler.py +0 -0
  132. {osism-0.20250824.0 → osism-0.20250824.1}/osism/utils/__init__.py +0 -0
  133. {osism-0.20250824.0 → osism-0.20250824.1}/osism/utils/ssh.py +0 -0
  134. {osism-0.20250824.0 → osism-0.20250824.1}/osism.egg-info/SOURCES.txt +0 -0
  135. {osism-0.20250824.0 → osism-0.20250824.1}/osism.egg-info/dependency_links.txt +0 -0
  136. {osism-0.20250824.0 → osism-0.20250824.1}/osism.egg-info/entry_points.txt +0 -0
  137. {osism-0.20250824.0 → osism-0.20250824.1}/osism.egg-info/not-zip-safe +0 -0
  138. {osism-0.20250824.0 → osism-0.20250824.1}/osism.egg-info/requires.txt +0 -0
  139. {osism-0.20250824.0 → osism-0.20250824.1}/osism.egg-info/top_level.txt +0 -0
  140. {osism-0.20250824.0 → osism-0.20250824.1}/playbooks/build.yml +0 -0
  141. {osism-0.20250824.0 → osism-0.20250824.1}/playbooks/pre.yml +0 -0
  142. {osism-0.20250824.0 → osism-0.20250824.1}/playbooks/test-setup.yml +0 -0
  143. {osism-0.20250824.0 → osism-0.20250824.1}/requirements.ansible.txt +0 -0
  144. {osism-0.20250824.0 → osism-0.20250824.1}/requirements.netbox-manager.txt +0 -0
  145. {osism-0.20250824.0 → osism-0.20250824.1}/requirements.openstack-flavor-manager.txt +0 -0
  146. {osism-0.20250824.0 → osism-0.20250824.1}/requirements.openstack-image-manager.txt +0 -0
  147. {osism-0.20250824.0 → osism-0.20250824.1}/requirements.txt +0 -0
  148. {osism-0.20250824.0 → osism-0.20250824.1}/requirements.yml +0 -0
  149. {osism-0.20250824.0 → osism-0.20250824.1}/setup.cfg +0 -0
  150. {osism-0.20250824.0 → osism-0.20250824.1}/setup.py +0 -0
@@ -0,0 +1 @@
1
+ Christian Berendt <berendt@osism.tech>
@@ -0,0 +1,7 @@
1
+ CHANGES
2
+ =======
3
+
4
+ v0.20250824.1
5
+ -------------
6
+
7
+ * frontend: improve baremetal nodes layout (#1672)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: osism
3
- Version: 0.20250824.0
3
+ Version: 0.20250824.1
4
4
  Summary: OSISM manager interface
5
5
  Home-page: https://github.com/osism/python-osism
6
6
  Author: OSISM GmbH
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { useState } from "react";
4
4
  import { useQuery } from "@tanstack/react-query";
5
- import { RefreshCw, Search, AlertCircle } from "lucide-react";
5
+ import { RefreshCw, Search, AlertCircle, ArrowUpDown } from "lucide-react";
6
6
  import api from "@/lib/api";
7
7
  import { BaremetalNode } from "@/lib/types";
8
8
 
@@ -11,6 +11,7 @@ export default function NodesPage() {
11
11
  const [filterProvisionState, setFilterProvisionState] = useState("all");
12
12
  const [filterPowerState, setFilterPowerState] = useState("all");
13
13
  const [filterMaintenance, setFilterMaintenance] = useState("all");
14
+ const [sortDirection, setSortDirection] = useState<"asc" | "desc">("asc");
14
15
 
15
16
  const { data, isLoading, error, refetch, isRefetching } = useQuery({
16
17
  queryKey: ["baremetal-nodes"],
@@ -18,23 +19,38 @@ export default function NodesPage() {
18
19
  refetchInterval: 60000,
19
20
  });
20
21
 
21
- const filteredNodes = data?.nodes.filter((node: BaremetalNode) => {
22
- const matchesSearch = searchTerm === "" ||
23
- (node.name && node.name.toLowerCase().includes(searchTerm.toLowerCase())) ||
24
- (node.uuid && node.uuid.toLowerCase().includes(searchTerm.toLowerCase()));
25
-
26
- const matchesProvisionState = filterProvisionState === "all" ||
27
- node.provision_state === filterProvisionState;
28
-
29
- const matchesPowerState = filterPowerState === "all" ||
30
- node.power_state === filterPowerState;
22
+ const filteredAndSortedNodes = data?.nodes
23
+ .filter((node: BaremetalNode) => {
24
+ const matchesSearch = searchTerm === "" ||
25
+ (node.name && node.name.toLowerCase().includes(searchTerm.toLowerCase())) ||
26
+ (node.uuid && node.uuid.toLowerCase().includes(searchTerm.toLowerCase()));
27
+
28
+ const matchesProvisionState = filterProvisionState === "all" ||
29
+ node.provision_state === filterProvisionState;
30
+
31
+ const matchesPowerState = filterPowerState === "all" ||
32
+ node.power_state === filterPowerState;
31
33
 
32
- const matchesMaintenance = filterMaintenance === "all" ||
33
- (filterMaintenance === "maintenance" && node.maintenance === true) ||
34
- (filterMaintenance === "active" && node.maintenance === false);
34
+ const matchesMaintenance = filterMaintenance === "all" ||
35
+ (filterMaintenance === "maintenance" && node.maintenance === true) ||
36
+ (filterMaintenance === "active" && node.maintenance === false);
35
37
 
36
- return matchesSearch && matchesProvisionState && matchesPowerState && matchesMaintenance;
37
- });
38
+ return matchesSearch && matchesProvisionState && matchesPowerState && matchesMaintenance;
39
+ })
40
+ .sort((a: BaremetalNode, b: BaremetalNode) => {
41
+ const nameA = a.name || a.uuid || '';
42
+ const nameB = b.name || b.uuid || '';
43
+
44
+ if (sortDirection === "asc") {
45
+ return nameA.localeCompare(nameB);
46
+ } else {
47
+ return nameB.localeCompare(nameA);
48
+ }
49
+ });
50
+
51
+ const toggleSortDirection = () => {
52
+ setSortDirection(prev => prev === "asc" ? "desc" : "asc");
53
+ };
38
54
 
39
55
  const uniqueProvisionStates = data ?
40
56
  [...new Set(data.nodes.map(n => n.provision_state).filter((state): state is string => Boolean(state)))] : [];
@@ -169,41 +185,40 @@ export default function NodesPage() {
169
185
  </div>
170
186
  </div>
171
187
  </div>
172
- ) : filteredNodes && filteredNodes.length > 0 ? (
188
+ ) : filteredAndSortedNodes && filteredAndSortedNodes.length > 0 ? (
173
189
  <div className="bg-white shadow overflow-hidden sm:rounded-md">
190
+ <div className="px-4 py-3 bg-gray-50 border-b border-gray-200">
191
+ <div className="flex items-center">
192
+ <button
193
+ onClick={toggleSortDirection}
194
+ className="flex items-center text-sm font-medium text-gray-700 hover:text-gray-900"
195
+ >
196
+ Name
197
+ <ArrowUpDown className="ml-1 h-4 w-4" />
198
+ <span className="ml-1 text-xs text-gray-500">
199
+ ({sortDirection === "asc" ? "A-Z" : "Z-A"})
200
+ </span>
201
+ </button>
202
+ </div>
203
+ </div>
174
204
  <ul className="divide-y divide-gray-200">
175
- {filteredNodes.map((node: BaremetalNode, index) => (
205
+ {filteredAndSortedNodes.map((node: BaremetalNode, index) => (
176
206
  <li key={node.uuid || `node-${index}`}>
177
207
  <div className="px-4 py-4 sm:px-6">
178
208
  <div className="flex items-center justify-between">
179
209
  <div className="flex-1">
180
- <div className="flex items-center">
181
- <p className="text-sm font-medium text-gray-900">
182
- {node.name || node.uuid}
183
- </p>
184
- {node.maintenance && (
185
- <span className="ml-2 px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-yellow-100 text-yellow-800">
186
- Maintenance
187
- </span>
188
- )}
189
- </div>
190
- <div className="mt-2 sm:flex sm:justify-between">
191
- <div className="sm:flex">
192
- <p className="flex items-center text-sm text-gray-500">
193
- UUID: {node.uuid}
210
+ <div className="flex items-center justify-between">
211
+ <div className="flex items-center">
212
+ <p className="text-sm font-medium text-gray-900">
213
+ {node.name || node.uuid}
194
214
  </p>
195
- {node.driver && (
196
- <p className="mt-2 flex items-center text-sm text-gray-500 sm:mt-0 sm:ml-6">
197
- Driver: {node.driver}
198
- </p>
199
- )}
200
- {node.resource_class && (
201
- <p className="mt-2 flex items-center text-sm text-gray-500 sm:mt-0 sm:ml-6">
202
- Resource Class: {node.resource_class}
203
- </p>
215
+ {node.maintenance && (
216
+ <span className="ml-2 px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-yellow-100 text-yellow-800">
217
+ Maintenance
218
+ </span>
204
219
  )}
205
220
  </div>
206
- <div className="mt-2 flex items-center text-sm sm:mt-0">
221
+ <div className="flex items-center gap-2">
207
222
  <span className={`px-2 inline-flex text-xs leading-5 font-semibold rounded-full ${
208
223
  node.power_state === "power on"
209
224
  ? "bg-green-100 text-green-800"
@@ -211,7 +226,7 @@ export default function NodesPage() {
211
226
  }`}>
212
227
  Power: {node.power_state || "unknown"}
213
228
  </span>
214
- <span className={`ml-2 px-2 inline-flex text-xs leading-5 font-semibold rounded-full ${
229
+ <span className={`px-2 inline-flex text-xs leading-5 font-semibold rounded-full ${
215
230
  node.provision_state === "active"
216
231
  ? "bg-blue-100 text-blue-800"
217
232
  : node.provision_state === "available"
@@ -226,6 +241,26 @@ export default function NodesPage() {
226
241
  </span>
227
242
  </div>
228
243
  </div>
244
+ <div className="mt-2 grid grid-cols-1 gap-x-4 gap-y-2 sm:grid-cols-2 lg:grid-cols-4">
245
+ <p className="flex items-center text-sm text-gray-500">
246
+ UUID: {node.uuid}
247
+ </p>
248
+ {node.driver && (
249
+ <p className="flex items-center text-sm text-gray-500">
250
+ Driver: {node.driver}
251
+ </p>
252
+ )}
253
+ {node.created_at && (
254
+ <p className="flex items-center text-sm text-gray-500">
255
+ Created: {new Date(node.created_at).toLocaleString()}
256
+ </p>
257
+ )}
258
+ {node.updated_at && (
259
+ <p className="flex items-center text-sm text-gray-500">
260
+ Updated: {new Date(node.updated_at).toLocaleString()}
261
+ </p>
262
+ )}
263
+ </div>
229
264
  {node.last_error && (
230
265
  <div className="mt-2">
231
266
  <p className="text-sm text-red-600">
@@ -250,7 +285,7 @@ export default function NodesPage() {
250
285
 
251
286
  {data && (
252
287
  <div className="mt-4 text-sm text-gray-600">
253
- Showing {filteredNodes?.length || 0} of {data.count} nodes
288
+ Showing {filteredAndSortedNodes?.length || 0} of {data.count} nodes
254
289
  </div>
255
290
  )}
256
291
  </div>
@@ -3,7 +3,7 @@ export interface BaremetalNode {
3
3
  name: string | null;
4
4
  power_state: string | null;
5
5
  provision_state: string | null;
6
- maintenance: boolean;
6
+ maintenance: boolean | null;
7
7
  instance_uuid: string | null;
8
8
  driver: string | null;
9
9
  resource_class: string | null;
@@ -84,20 +84,21 @@ def get_baremetal_nodes():
84
84
  # Convert generator to list and extract relevant fields
85
85
  node_list = []
86
86
  for node in nodes:
87
+ # OpenStack SDK returns Resource objects, not dicts - use attribute access
87
88
  node_info = {
88
- "uuid": node.get("uuid"),
89
- "name": node.get("name"),
90
- "power_state": node.get("power_state"),
91
- "provision_state": node.get("provision_state"),
92
- "maintenance": node.get("maintenance"),
93
- "instance_uuid": node.get("instance_uuid"),
94
- "driver": node.get("driver"),
95
- "resource_class": node.get("resource_class"),
96
- "properties": node.get("properties", {}),
97
- "extra": node.get("extra", {}),
98
- "last_error": node.get("last_error"),
99
- "created_at": node.get("created_at"),
100
- "updated_at": node.get("updated_at"),
89
+ "uuid": getattr(node, "uuid", None) or getattr(node, "id", None),
90
+ "name": getattr(node, "name", None),
91
+ "power_state": getattr(node, "power_state", None),
92
+ "provision_state": getattr(node, "provision_state", None),
93
+ "maintenance": getattr(node, "maintenance", None),
94
+ "instance_uuid": getattr(node, "instance_uuid", None),
95
+ "driver": getattr(node, "driver", None),
96
+ "resource_class": getattr(node, "resource_class", None),
97
+ "properties": getattr(node, "properties", {}),
98
+ "extra": getattr(node, "extra", {}),
99
+ "last_error": getattr(node, "last_error", None),
100
+ "created_at": getattr(node, "created_at", None),
101
+ "updated_at": getattr(node, "updated_at", None),
101
102
  }
102
103
  node_list.append(node_info)
103
104
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: osism
3
- Version: 0.20250824.0
3
+ Version: 0.20250824.1
4
4
  Summary: OSISM manager interface
5
5
  Home-page: https://github.com/osism/python-osism
6
6
  Author: OSISM GmbH
@@ -0,0 +1 @@
1
+ {"git_version": "2d93840", "is_release": false}
@@ -1 +0,0 @@
1
- renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
@@ -1,7 +0,0 @@
1
- CHANGES
2
- =======
3
-
4
- v0.20250824.0
5
- -------------
6
-
7
- * chore(deps): update dependency websockets to v15 (#1667)
@@ -1 +0,0 @@
1
- {"git_version": "0dfd880", "is_release": false}
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes