feat: Removes api routes and controller as they're currently not used.
All checks were successful
CI / Linux Tests (push) Successful in 5m30s

This commit is contained in:
2026-01-30 17:10:14 -05:00
parent b359a3317f
commit a3fb87f86e
15 changed files with 42 additions and 761 deletions

View File

@@ -1,38 +0,0 @@
import Dependencies
import DependenciesMacros
import Logging
import ManualDCore
extension DependencyValues {
public var apiController: ApiController {
get { self[ApiController.self] }
set { self[ApiController.self] = newValue }
}
}
@DependencyClient
public struct ApiController: Sendable {
public var json: @Sendable (Request) async throws -> (any Encodable)?
}
extension ApiController {
public struct Request: Sendable {
public let route: SiteRoute.Api
public let logger: Logger
public init(route: SiteRoute.Api, logger: Logger) {
self.route = route
self.logger = logger
}
}
}
extension ApiController: DependencyKey {
public static let testValue = Self()
public static let liveValue = Self(
json: { request in
try await request.route.respond(logger: request.logger)
}
)
}

View File

@@ -1,129 +0,0 @@
import DatabaseClient
import Dependencies
import Logging
import ManualDCore
extension SiteRoute.Api {
func respond(logger: Logger) async throws -> (any Encodable)? {
switch self {
case .project(let route):
return try await route.respond(logger: logger)
case .room(let route):
return try await route.respond(logger: logger)
case .equipment(let route):
return try await route.respond(logger: logger)
case .componentLoss(let route):
return try await route.respond(logger: logger)
}
}
}
extension SiteRoute.Api.ProjectRoute {
func respond(logger: Logger) async throws -> (any Encodable)? {
@Dependency(\.database) var database
switch self {
case .create(let request):
// return try await database.projects.create(request)
// FIX:
fatalError()
case .delete(let id):
try await database.projects.delete(id)
return nil
case .detail(let id, let route):
switch route {
case .index:
return try await database.projects.detail(id)
case .completedSteps:
// FIX:
fatalError()
}
case .get(let id):
guard let project = try await database.projects.get(id) else {
logger.error("Project not found for id: \(id)")
throw ApiError("Project not found.")
}
return project
case .index:
// FIX: Fix to return projects.
return [Project]()
}
}
}
extension SiteRoute.Api.RoomRoute {
func respond(logger: Logger) async throws -> (any Encodable)? {
@Dependency(\.database) var database
switch self {
case .create(let request):
return try await database.rooms.create(request)
case .delete(let id):
try await database.rooms.delete(id)
return nil
case .get(let id):
guard let room = try await database.rooms.get(id) else {
logger.error("Room not found for id: \(id)")
throw ApiError("Room not found.")
}
return room
}
}
}
extension SiteRoute.Api.EquipmentRoute {
func respond(logger: Logger) async throws -> (any Encodable)? {
@Dependency(\.database) var database
switch self {
case .create(let request):
return try await database.equipment.create(request)
case .delete(let id):
try await database.equipment.delete(id)
return nil
case .fetch(let projectID):
return try await database.equipment.fetch(projectID)
case .get(let id):
guard let room = try await database.equipment.get(id) else {
logger.error("Equipment not found for id: \(id)")
throw ApiError("Equipment not found.")
}
return room
}
}
}
extension SiteRoute.Api.ComponentLossRoute {
func respond(logger: Logger) async throws -> (any Encodable)? {
@Dependency(\.database) var database
switch self {
case .create(let request):
return try await database.componentLosses.create(request)
case .delete(let id):
try await database.componentLosses.delete(id)
return nil
case .fetch(let projectID):
return try await database.componentLosses.fetch(projectID)
case .get(let id):
guard let room = try await database.componentLosses.get(id) else {
logger.error("Component loss not found for id: \(id)")
throw ApiError("Component loss not found.")
}
return room
}
}
}
public struct ApiError: Error {
let message: String
init(_ message: String) {
self.message = message
}
}

View File

@@ -1,37 +1,37 @@
import ApiController
import ManualDCore
import Vapor
extension ApiController {
func respond(_ route: SiteRoute.Api, request: Vapor.Request) async throws
-> any AsyncResponseEncodable
{
guard let encodable = try await json(.init(route: route, logger: request.logger)) else {
return HTTPStatus.ok
}
return AnyJSONResponse(value: encodable)
}
}
struct AnyJSONResponse: AsyncResponseEncodable {
public var headers: HTTPHeaders = ["Content-Type": "application/json"]
let value: any Encodable
init(additionalHeaders: HTTPHeaders = [:], value: any Encodable) {
if additionalHeaders.contains(name: .contentType) {
self.headers = additionalHeaders
} else {
headers.add(contentsOf: additionalHeaders)
}
self.value = value
}
func encodeResponse(for request: Request) async throws -> Response {
try Response(
status: .ok,
headers: headers,
body: .init(data: JSONEncoder().encode(value))
)
}
}
// import ApiController
// import ManualDCore
// import Vapor
//
// extension ApiController {
//
// func respond(_ route: SiteRoute.Api, request: Vapor.Request) async throws
// -> any AsyncResponseEncodable
// {
// guard let encodable = try await json(.init(route: route, logger: request.logger)) else {
// return HTTPStatus.ok
// }
// return AnyJSONResponse(value: encodable)
// }
// }
//
// struct AnyJSONResponse: AsyncResponseEncodable {
// public var headers: HTTPHeaders = ["Content-Type": "application/json"]
// let value: any Encodable
//
// init(additionalHeaders: HTTPHeaders = [:], value: any Encodable) {
// if additionalHeaders.contains(name: .contentType) {
// self.headers = additionalHeaders
// } else {
// headers.add(contentsOf: additionalHeaders)
// }
// self.value = value
// }
//
// func encodeResponse(for request: Request) async throws -> Response {
// try Response(
// status: .ok,
// headers: headers,
// body: .init(data: JSONEncoder().encode(value))
// )
// }
// }

View File

@@ -1,4 +1,4 @@
import ApiController
// import ApiController
import AuthClient
import DatabaseClient
import Dependencies
@@ -12,17 +12,17 @@ import ViewController
struct DependenciesMiddleware: AsyncMiddleware {
private let values: DependencyValues.Continuation
private let apiController: ApiController
// private let apiController: ApiController
private let database: DatabaseClient
private let viewController: ViewController
init(
database: DatabaseClient,
apiController: ApiController = .liveValue,
// apiController: ApiController = .liveValue,
viewController: ViewController = .liveValue
) {
self.values = withEscapedDependencies { $0 }
self.apiController = apiController
// self.apiController = apiController
self.database = database
self.viewController = viewController
}
@@ -30,7 +30,7 @@ struct DependenciesMiddleware: AsyncMiddleware {
func respond(to request: Request, chainingTo next: any AsyncResponder) async throws -> Response {
try await values.yield {
try await withDependencies {
$0.apiController = apiController
// $0.apiController = apiController
$0.auth = .live(on: request)
$0.database = database
// $0.dateFormatter = .liveValue

View File

@@ -100,8 +100,6 @@ extension SiteRoute {
fileprivate func middleware() -> [any Middleware]? {
switch self {
case .api:
return nil
case .health:
return nil
case .view(let route):
@@ -117,13 +115,10 @@ private func siteHandler(
request: Request,
route: SiteRoute
) async throws -> any AsyncResponseEncodable {
@Dependency(\.apiController) var apiController
@Dependency(\.viewController) var viewController
@Dependency(\.projectClient) var projectClient
switch route {
case .api(let route):
return try await apiController.respond(route, request: request)
case .health:
return HTTPStatus.ok
// Generating a pdf return's a `Response` instead of `HTML` like other views, so we

View File

@@ -1,270 +0,0 @@
import CasePathsCore
import Foundation
@preconcurrency import URLRouting
extension SiteRoute {
/// Represents api routes.
///
/// The routes return json as opposed to view routes that return html.
public enum Api: Sendable, Equatable {
case project(Self.ProjectRoute)
case room(Self.RoomRoute)
case equipment(Self.EquipmentRoute)
case componentLoss(Self.ComponentLossRoute)
public static let rootPath = Path {
"api"
"v1"
}
public static let router = OneOf {
Route(.case(Self.project)) {
rootPath
ProjectRoute.router
}
Route(.case(Self.room)) {
rootPath
RoomRoute.router
}
Route(.case(Self.equipment)) {
rootPath
EquipmentRoute.router
}
Route(.case(Self.componentLoss)) {
rootPath
ComponentLossRoute.router
}
}
}
}
extension SiteRoute.Api {
public enum ProjectRoute: Sendable, Equatable {
case create(Project.Create)
case delete(id: Project.ID)
case detail(id: Project.ID, route: DetailRoute)
case get(id: Project.ID)
case index
static let rootPath = "projects"
public static let router = OneOf {
Route(.case(Self.create)) {
Path { rootPath }
Method.post
Body(.json(Project.Create.self))
}
Route(.case(Self.delete(id:))) {
Path {
rootPath
Project.ID.parser()
}
Method.delete
}
Route(.case(Self.get(id:))) {
Path {
rootPath
Project.ID.parser()
}
Method.get
}
Route(.case(Self.index)) {
Path { rootPath }
Method.get
}
Route(.case(Self.detail(id:route:))) {
Path {
rootPath
Project.ID.parser()
}
DetailRoute.router
}
}
}
}
extension SiteRoute.Api.ProjectRoute {
public enum DetailRoute: Equatable, Sendable {
case index
case completedSteps
static let rootPath = "details"
static let router = OneOf {
Route(.case(Self.index)) {
Path { rootPath }
Method.get
}
Route(.case(Self.completedSteps)) {
Path {
rootPath
"completed"
}
Method.get
}
}
}
}
extension SiteRoute.Api {
public enum RoomRoute: Sendable, Equatable {
case create(Room.Create)
case delete(id: Room.ID)
case get(id: Room.ID)
static let rootPath = "rooms"
public static let router = OneOf {
Route(.case(Self.create)) {
Path { rootPath }
Method.post
Body(.json(Room.Create.self))
}
Route(.case(Self.delete(id:))) {
Path {
rootPath
Room.ID.parser()
}
Method.delete
}
Route(.case(Self.get(id:))) {
Path {
rootPath
Room.ID.parser()
}
Method.get
}
}
}
}
extension SiteRoute.Api {
public enum EquipmentRoute: Sendable, Equatable {
case create(EquipmentInfo.Create)
case delete(id: EquipmentInfo.ID)
case fetch(projectID: Project.ID)
case get(id: EquipmentInfo.ID)
static let rootPath = "equipment"
public static let router = OneOf {
Route(.case(Self.create)) {
Path { rootPath }
Method.post
Body(.json(EquipmentInfo.Create.self))
}
Route(.case(Self.delete(id:))) {
Path {
rootPath
EquipmentInfo.ID.parser()
}
Method.delete
}
Route(.case(Self.fetch(projectID:))) {
Path { rootPath }
Method.get
Query {
Field("projectID") { Project.ID.parser() }
}
}
Route(.case(Self.get(id:))) {
Path {
rootPath
EquipmentInfo.ID.parser()
}
Method.get
}
}
}
}
extension SiteRoute.Api {
public enum ComponentLossRoute: Sendable, Equatable {
case create(ComponentPressureLoss.Create)
case delete(id: ComponentPressureLoss.ID)
case fetch(projectID: Project.ID)
case get(id: ComponentPressureLoss.ID)
static let rootPath = "componentLoss"
public static let router = OneOf {
Route(.case(Self.create)) {
Path { rootPath }
Method.post
Body(.json(ComponentPressureLoss.Create.self))
}
Route(.case(Self.delete(id:))) {
Path {
rootPath
ComponentPressureLoss.ID.parser()
}
Method.delete
}
Route(.case(Self.fetch(projectID:))) {
Path { rootPath }
Method.get
Query {
Field("projectID") { Project.ID.parser() }
}
}
Route(.case(Self.get(id:))) {
Path {
rootPath
ComponentPressureLoss.ID.parser()
}
Method.get
}
}
}
}
extension SiteRoute.Api {
public enum EffectiveLengthRoute: Equatable, Sendable {
case create(EquivalentLength.Create)
case delete(id: EquivalentLength.ID)
case fetch(projectID: Project.ID)
case get(id: EquivalentLength.ID)
static let rootPath = "effectiveLength"
public static let router = OneOf {
Route(.case(Self.create)) {
Path {
rootPath
"create"
}
Method.post
Body(.json(EquivalentLength.Create.self))
}
Route(.case(Self.delete(id:))) {
Path {
rootPath
EquivalentLength.ID.parser()
}
Method.delete
}
Route(.case(Self.fetch(projectID:))) {
Path {
rootPath
}
Method.get
Query {
Field("projectID") { Project.ID.parser() }
}
}
Route(.case(Self.get(id:))) {
Path {
rootPath
EquivalentLength.ID.parser()
}
Method.get
}
}
}
}

View File

@@ -5,14 +5,10 @@ import Foundation
public enum SiteRoute: Equatable, Sendable {
case api(Self.Api)
case health
case view(Self.View)
public static let router = OneOf {
Route(.case(Self.api)) {
SiteRoute.Api.router
}
Route(.case(Self.health)) {
Path { "health" }
Method.get

View File

@@ -27,11 +27,4 @@ extension Badge where Inner == Number {
self.inner = Number(number, digits: digits)
}
public init<T>(number: Tagged<T, Int>) {
self.inner = Number(number.rawValue)
}
public init<T>(number: Tagged<T, Double>, digits: Int = 2) {
self.inner = Number(number.rawValue, digits: digits)
}
}

View File

@@ -26,32 +26,6 @@ public struct SubmitButton: HTML, Sendable {
}
}
public struct CancelButton: HTML, Sendable {
let title: String
let type: HTMLAttribute<HTMLTag.button>.ButtonType
public init(
title: String = "Cancel",
type: HTMLAttribute<HTMLTag.button>.ButtonType = .button
) {
self.title = title
self.type = type
}
public var body: some HTML<HTMLTag.button> {
button(
.class(
"""
text-white font-bold text-xl bg-red-500 hover:bg-red-600 px-4 py-2 rounded-lg shadow-lg
"""
),
.type(type)
) {
title
}
}
}
public struct EditButton: HTML, Sendable {
let title: String?
let type: HTMLAttribute<HTMLTag.button>.ButtonType

View File

@@ -9,13 +9,6 @@ extension HTMLAttribute where Tag: HTMLTrait.Attributes.href {
}
}
extension HTMLAttribute where Tag == HTMLTag.form {
public static func action(route: SiteRoute.View) -> Self {
action(SiteRoute.View.router.path(for: route))
}
}
extension HTMLAttribute where Tag == HTMLTag.input {
public static func value(_ string: String?) -> Self {
@@ -42,9 +35,6 @@ extension HTMLAttribute where Tag == HTMLTag.button {
}
extension HTML where Tag: HTMLTrait.Attributes.Global {
public func badge() -> _AttributedElement<Self> {
attributes(.class("badge badge-lg badge-outline"))
}
public func hidden(when shouldHide: Bool) -> _AttributedElement<Self> {
attributes(.class("hidden"), when: shouldHide)

View File

@@ -1,45 +0,0 @@
import Elementary
// TODO: Remove, using svg's.
public struct Icon: HTML, Sendable {
let icon: String
public init(icon: String) {
self.icon = icon
}
public var body: some HTML {
i(.data("lucide", value: icon)) {}
}
}
extension Icon {
public init(_ icon: Key) {
self.init(icon: icon.icon)
}
public enum Key: String {
case circlePlus
case close
case doorClosed
case mapPin
case rulerDimensionLine
case squareFunction
case wind
var icon: String {
switch self {
case .circlePlus: return "circle-plus"
case .close: return "x"
case .doorClosed: return "door-closed"
case .mapPin: return "map-pin"
case .rulerDimensionLine: return "ruler-dimension-line"
case .squareFunction: return "square-function"
case .wind: return rawValue
}
}
}
}

View File

@@ -21,60 +21,6 @@ public struct LabeledInput: HTML, Sendable {
}
}
public struct Input: HTML, Sendable {
let id: String?
let name: String?
let placeholder: String
private var _name: String {
guard let name else {
return id ?? ""
}
return name
}
init(
id: String? = nil,
name: String? = nil,
placeholder: String
) {
self.id = id
self.name = name
self.placeholder = placeholder
}
public init(
id: String,
name: String? = nil,
placeholder: String
) {
self.id = id
self.name = name
self.placeholder = placeholder
}
public init(
name: String,
placeholder: String
) {
self.init(id: nil, name: name, placeholder: placeholder)
}
public var body: some HTML<HTMLTag.input> {
input(
.id(id ?? ""), .name(_name), .placeholder(placeholder),
.class(
"""
input w-full rounded-md bg-white px-3 py-1.5 text-slate-900 outline-1
-outline-offset-1 outline-slate-300 focus:outline focus:-outline-offset-2
focus:outline-indigo-600 invalid:border-red-500 out-of-range:border-red-500
"""
)
)
}
}
extension HTMLAttribute where Tag == HTMLTag.input {
public static func max(_ value: String) -> Self {

View File

@@ -6,15 +6,6 @@ public struct Number: HTML, Sendable {
let fractionDigits: Int
let value: Double
// private var formatter: NumberFormatter {
// let formatter = NumberFormatter()
// formatter.maximumFractionDigits = fractionDigits
// formatter.numberStyle = .decimal
// formatter.groupingSize = 3
// formatter.groupingSeparator = ","
// return formatter
// }
public init(
_ value: Double,
digits fractionDigits: Int = 2