Skip to content

Commit

Permalink
feat: Possibility to configure time zone and timestamp locale
Browse files Browse the repository at this point in the history
  • Loading branch information
vehagn committed May 8, 2024
1 parent e2f4f3f commit ac39c23
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 7 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ Docker Swarm Dashboard supports environment variables for configuration
* `DSD_HANDLE_LOGS`: Set to `false` to prevent fetching and displaying logs.
* `DSD_DASHBOARD_LAYOUT`: Default dashboard layout. Either `row` (default) or `column`.
* `DSD_HIDE_SERVICE_STATES`: Comma-separated list of states to not show in the main dashboard.
* `LOCALE`: Timestamp format based on a [BCP 47](https://www.rfc-editor.org/bcp/bcp47.txt) language tag.
* `TZ`: [IANA Time zone](https://www.iana.org/time-zones) to display timestamps in.

### Pull Image from ghcr.io
```
Expand Down
7 changes: 5 additions & 2 deletions app-src/src/common/DefaultDateTimeFormat.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ const DEFAULT_DATE_TIME_FORMAT = {
second: '2-digit',
}

export const toDefaultDateTimeString = (date) => {
return date.toLocaleString(undefined, DEFAULT_DATE_TIME_FORMAT)
export const toDefaultDateTimeString = (date, locale, timeZone) => {
return date.toLocaleString(
locale ? locale : undefined,
timeZone ? { timeZone: timeZone } : DEFAULT_DATE_TIME_FORMAT,
)
}
19 changes: 17 additions & 2 deletions app-src/src/components/ServiceStatusBadge.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { Badge, OverlayTrigger, Tooltip } from 'react-bootstrap'
import { getStyleClassForState } from '../Helper'
import PropTypes from 'prop-types'
import { toDefaultDateTimeString } from '../common/DefaultDateTimeFormat'
import { useAtomValue } from 'jotai'
import { dashboardSettingsAtom } from '../common/store/atoms'

const ServiceStatusBadge = ({
id,
Expand All @@ -14,6 +16,7 @@ const ServiceStatusBadge = ({
if (hiddenStates.includes(serviceState)) {
return
}
const dashBoardSettings = useAtomValue(dashboardSettingsAtom)
if (createdAt || updatedAt || serviceError) {
return (
<OverlayTrigger
Expand All @@ -23,13 +26,25 @@ const ServiceStatusBadge = ({
<Tooltip id={`tooltip-task-status-sate-${id}`}>
{createdAt && (
<span>
Created at: {toDefaultDateTimeString(new Date(createdAt))}
Created at:{' '}
{toDefaultDateTimeString(
new Date(createdAt),
dashBoardSettings.locale,
dashBoardSettings.timeZone,
)}
<br />
{createdAt}
<br />
</span>
)}
{updatedAt && (
<span>
Updated at: {toDefaultDateTimeString(new Date(updatedAt))}
Updated at:{' '}
{toDefaultDateTimeString(
new Date(updatedAt),
dashBoardSettings.locale,
dashBoardSettings.timeZone,
)}
<br />
</span>
)}
Expand Down
18 changes: 16 additions & 2 deletions app-src/src/components/StacksComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { toDefaultDateTimeString } from '../common/DefaultDateTimeFormat'
import {
currentVariantAtom,
currentVariantClassesAtom,
dashboardSettingsAtom,
stacksAtom,
viewAtom,
} from '../common/store/atoms'
Expand All @@ -12,6 +13,7 @@ import { servicesDetailId } from '../common/navigationConstants'
function StacksComponent() {
const currentVariant = useAtomValue(currentVariantAtom)
const currentVariantClasses = useAtomValue(currentVariantClassesAtom)
const dashBoardSettings = useAtomValue(dashboardSettingsAtom)

let stacks
const stacksData = useAtomValue(stacksAtom)
Expand All @@ -28,8 +30,20 @@ function StacksComponent() {
{service['ShortName'] ? service['ShortName'] : service['ServiceName']}
</td>
<td>{service['Replication']}</td>
<td>{toDefaultDateTimeString(new Date(service['Created']))}</td>
<td>{toDefaultDateTimeString(new Date(service['Updated']))}</td>
<td>
{toDefaultDateTimeString(
new Date(service['Created']),
dashBoardSettings.locale,
dashBoardSettings.timeZone,
)}
</td>
<td>
{toDefaultDateTimeString(
new Date(service['Updated']),
dashBoardSettings.locale,
dashBoardSettings.timeZone,
)}
</td>
</tr>
))
}
Expand Down
10 changes: 9 additions & 1 deletion app-src/src/components/TasksComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { nodesDetailId, servicesDetailId } from '../common/navigationConstants'
import {
currentVariantAtom,
currentVariantClassesAtom,
dashboardSettingsAtom,
tableSizeAtom,
tasksAtomNew,
viewAtom,
Expand All @@ -16,6 +17,7 @@ function TasksComponent() {
const currentVariant = useAtomValue(currentVariantAtom)
const currentVariantClasses = useAtomValue(currentVariantClassesAtom)
const tableSize = useAtomValue(tableSizeAtom)
const dashBoardSettings = useAtomValue(dashboardSettingsAtom)

let rows

Expand All @@ -25,7 +27,13 @@ function TasksComponent() {
key={'tasksTable-' + task['ID']}
className={task['State'] === 'failed' ? 'table-danger' : null}
>
<td>{toDefaultDateTimeString(new Date(task['Timestamp']))}</td>
<td>
{toDefaultDateTimeString(
new Date(task['Timestamp']),
dashBoardSettings.locale,
dashBoardSettings.timeZone,
)}
</td>
<td>
<ServiceStatusBadge id={id} serviceState={task['State']} />
</td>
Expand Down
14 changes: 14 additions & 0 deletions server-src/dashboardsettingshandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,16 @@ type dashboardSettings struct {
ShowLogsButton bool `json:"showLogsButton"`
DefaultLayout string `json:"defaultLayout"`
HiddenServiceStates []string `json:"hiddenServiceStates"`
TimeZone *string `json:"timeZone"`
Locale *string `json:"locale"`
}

var (
handlingLogs = true
dashboardLayout = "row"
hiddenServiceStates = make([]string, 0)
timeZone = new(string)
locale = new(string)
)

func init() {
Expand All @@ -37,13 +41,23 @@ func init() {
}
}

if timeZoneEnvValue, timeZoneSet := os.LookupEnv("TZ"); timeZoneSet {
timeZone = &timeZoneEnvValue
}

if localeEnvValue, localeSet := os.LookupEnv("LOCALE"); localeSet {
locale = &localeEnvValue
}

}

func dashboardSettingsHandler(w http.ResponseWriter, _ *http.Request) {
jsonString, _ := json.Marshal(dashboardSettings{
handlingLogs,
dashboardLayout,
hiddenServiceStates,
timeZone,
locale,
})
w.Header().Set("Content-Type", "application/json")
w.Write(jsonString)
Expand Down

0 comments on commit ac39c23

Please sign in to comment.