feat: Removes api routes and controller as they're currently not used.
All checks were successful
CI / Linux Tests (push) Successful in 5m30s
All checks were successful
CI / Linux Tests (push) Successful in 5m30s
This commit is contained in:
@@ -6,7 +6,6 @@ let package = Package(
|
||||
name: "swift-manual-d",
|
||||
products: [
|
||||
.executable(name: "App", targets: ["App"]),
|
||||
.library(name: "ApiController", targets: ["ApiController"]),
|
||||
.library(name: "AuthClient", targets: ["AuthClient"]),
|
||||
.library(name: "DatabaseClient", targets: ["DatabaseClient"]),
|
||||
.library(name: "EnvClient", targets: ["EnvClient"]),
|
||||
@@ -38,7 +37,6 @@ let package = Package(
|
||||
.executableTarget(
|
||||
name: "App",
|
||||
dependencies: [
|
||||
.target(name: "ApiController"),
|
||||
.target(name: "AuthClient"),
|
||||
.target(name: "DatabaseClient"),
|
||||
.target(name: "ViewController"),
|
||||
@@ -52,22 +50,6 @@ let package = Package(
|
||||
.product(name: "VaporRouting", package: "vapor-routing"),
|
||||
]
|
||||
),
|
||||
.target(
|
||||
name: "ApiController",
|
||||
dependencies: [
|
||||
.target(name: "DatabaseClient"),
|
||||
.target(name: "ManualDCore"),
|
||||
.product(name: "Dependencies", package: "swift-dependencies"),
|
||||
.product(name: "DependenciesMacros", package: "swift-dependencies"),
|
||||
.product(name: "Vapor", package: "vapor"),
|
||||
]
|
||||
),
|
||||
.testTarget(
|
||||
name: "ApiRouteTests",
|
||||
dependencies: [
|
||||
.target(name: "ManualDCore")
|
||||
]
|
||||
),
|
||||
.target(
|
||||
name: "AuthClient",
|
||||
dependencies: [
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
import Dependencies
|
||||
import Foundation
|
||||
import ManualDCore
|
||||
import Testing
|
||||
import URLRouting
|
||||
|
||||
@Suite("ProjectRouteTests")
|
||||
struct ProjectRouteTests {
|
||||
let router = SiteRoute.Api.router
|
||||
|
||||
@Test
|
||||
func create() throws {
|
||||
let json = """
|
||||
{
|
||||
\"name\": \"Test\",
|
||||
\"streetAddress\": \"1234 Seasme Street\",
|
||||
\"city\": \"Nowhere\",
|
||||
\"state\": \"OH\",
|
||||
\"zipCode\": \"55555\"
|
||||
}
|
||||
"""
|
||||
var request = URLRequestData(
|
||||
method: "POST",
|
||||
path: "/api/v1/projects",
|
||||
body: .init(json.utf8)
|
||||
)
|
||||
let route = try router.parse(&request)
|
||||
#expect(
|
||||
route
|
||||
== .project(
|
||||
.create(
|
||||
.init(
|
||||
name: "Test",
|
||||
streetAddress: "1234 Seasme Street",
|
||||
city: "Nowhere",
|
||||
state: "OH",
|
||||
zipCode: "55555"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
func delete() throws {
|
||||
let id = UUID(0)
|
||||
var request = URLRequestData(
|
||||
method: "DELETE",
|
||||
path: "/api/v1/projects/\(id)"
|
||||
)
|
||||
let route = try router.parse(&request)
|
||||
#expect(route == .project(.delete(id: id)))
|
||||
}
|
||||
|
||||
@Test
|
||||
func get() throws {
|
||||
let id = UUID(0)
|
||||
var request = URLRequestData(
|
||||
method: "GET",
|
||||
path: "/api/v1/projects/\(id)"
|
||||
)
|
||||
let route = try router.parse(&request)
|
||||
#expect(route == .project(.get(id: id)))
|
||||
}
|
||||
|
||||
@Test
|
||||
func index() throws {
|
||||
var request = URLRequestData(
|
||||
method: "GET",
|
||||
path: "/api/v1/projects"
|
||||
)
|
||||
let route = try router.parse(&request)
|
||||
#expect(route == .project(.index))
|
||||
}
|
||||
|
||||
@Test
|
||||
func formData() throws {
|
||||
let p = Body {
|
||||
FormData {
|
||||
Optionally {
|
||||
Field("id", default: nil) { EquivalentLength.ID.parser() }
|
||||
}
|
||||
Field("name", .string)
|
||||
Field("type") { EquivalentLength.EffectiveLengthType.parser() }
|
||||
Many {
|
||||
Field("straightLengths") {
|
||||
Int.parser()
|
||||
}
|
||||
}
|
||||
}
|
||||
.map(.memberwise(SiteRoute.View.ProjectRoute.EquivalentLengthRoute.StepTwo.init))
|
||||
}
|
||||
|
||||
var request = URLRequestData(
|
||||
body: .init(
|
||||
"name=Test&type=supply&straightLengths=20&straightLengths=10"
|
||||
.utf8
|
||||
)
|
||||
)
|
||||
let value = try p.parse(&request)
|
||||
print(value)
|
||||
#expect(value.straightLengths == [20, 10])
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user