diff --git a/dbal/cpp/src/daemon/server_helpers/serialization.cpp b/dbal/cpp/src/daemon/server_helpers/serialization.cpp new file mode 100644 index 000000000..213a97f11 --- /dev/null +++ b/dbal/cpp/src/daemon/server_helpers/serialization.cpp @@ -0,0 +1,66 @@ +#include "server_helpers/serialization.hpp" + +#include +#include + +namespace dbal { +namespace daemon { + +long long timestamp_to_epoch_ms(const Timestamp& timestamp) { + return std::chrono::duration_cast(timestamp.time_since_epoch()).count(); +} + +Json::Value user_to_json(const User& user) { + Json::Value value(Json::objectValue); + value["id"] = user.id; + value["username"] = user.username; + value["email"] = user.email; + value["role"] = role_to_string(user.role); + value["createdAt"] = static_cast(timestamp_to_epoch_ms(user.created_at)); + value["updatedAt"] = static_cast(timestamp_to_epoch_ms(user.updated_at)); + return value; +} + +Json::Value users_to_json(const std::vector& users) { + Json::Value arr(Json::arrayValue); + for (const auto& user : users) { + arr.append(user_to_json(user)); + } + return arr; +} + +ListOptions list_options_from_json(const Json::Value& json) { + ListOptions options; + if (!json.isNull()) { + if (json.isMember("page") && json["page"].isInt()) { + options.page = json["page"].asInt(); + } + if (json.isMember("limit") && json["limit"].isInt()) { + options.limit = json["limit"].asInt(); + } + if (json.isMember("filter") && json["filter"].isObject()) { + for (const auto& key : json["filter"].getMemberNames()) { + options.filter[key] = json["filter"][key].asString(); + } + } + if (json.isMember("sort") && json["sort"].isObject()) { + for (const auto& key : json["sort"].getMemberNames()) { + options.sort[key] = json["sort"][key].asString(); + } + } + } + return options; +} + +Json::Value list_response_value(const std::vector& users, const ListOptions& options) { + Json::Value value(Json::objectValue); + value["data"] = users_to_json(users); + value["total"] = static_cast(users.size()); + value["page"] = options.page; + value["limit"] = options.limit; + value["hasMore"] = Json::Value(false); + return value; +} + +} // namespace daemon +} // namespace dbal diff --git a/frontends/dbal/app/globals.css b/frontends/dbal/app/globals.css index f6a8a94d2..186f3e1ed 100644 --- a/frontends/dbal/app/globals.css +++ b/frontends/dbal/app/globals.css @@ -11,9 +11,12 @@ box-sizing: border-box; } -body { - margin: 0; - min-height: 100vh; - background-color: theme('colors.background'); - color: theme('colors.foreground'); +@layer base { + body { + margin: 0; + min-height: 100vh; + background-color: theme('colors.background'); + color: theme('colors.foreground'); + font-family: var(--font-body); + } } diff --git a/frontends/dbal/app/layout.tsx b/frontends/dbal/app/layout.tsx index 1d505d2db..296c9935d 100644 --- a/frontends/dbal/app/layout.tsx +++ b/frontends/dbal/app/layout.tsx @@ -1,4 +1,5 @@ import type { Metadata } from 'next' +import type { ReactNode } from 'react' import { IBM_Plex_Sans, Space_Grotesk } from 'next/font/google' import './globals.css' @@ -20,7 +21,7 @@ export const metadata: Metadata = { export default function RootLayout({ children, }: { - children: React.ReactNode + children: ReactNode }) { return (