feat: Begins snapshot testing for html
This commit is contained in:
@@ -50,12 +50,25 @@ let package = Package(
|
|||||||
],
|
],
|
||||||
swiftSettings: swiftSettings
|
swiftSettings: swiftSettings
|
||||||
),
|
),
|
||||||
|
.testTarget(
|
||||||
|
name: "AppTests",
|
||||||
|
dependencies: [
|
||||||
|
.target(name: "App"),
|
||||||
|
.target(name: "HtmlSnapshotTesting"),
|
||||||
|
.product(name: "XCTVapor", package: "vapor")
|
||||||
|
],
|
||||||
|
resources: [
|
||||||
|
.copy("__Snapshots__")
|
||||||
|
],
|
||||||
|
swiftSettings: swiftSettings
|
||||||
|
),
|
||||||
.testTarget(
|
.testTarget(
|
||||||
name: "ViewRouteTests",
|
name: "ViewRouteTests",
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.target(name: "App"),
|
.target(name: "App"),
|
||||||
.product(name: "VaporTesting", package: "vapor")
|
.product(name: "VaporTesting", package: "vapor")
|
||||||
],
|
],
|
||||||
|
|
||||||
swiftSettings: swiftSettings
|
swiftSettings: swiftSettings
|
||||||
),
|
),
|
||||||
.testTarget(
|
.testTarget(
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import Dependencies
|
||||||
import Elementary
|
import Elementary
|
||||||
import Vapor
|
import Vapor
|
||||||
import VaporElementary
|
import VaporElementary
|
||||||
|
|||||||
@@ -8,15 +8,19 @@ import Vapor
|
|||||||
struct DependenciesMiddleware: AsyncMiddleware {
|
struct DependenciesMiddleware: AsyncMiddleware {
|
||||||
|
|
||||||
private let values: DependencyValues.Continuation
|
private let values: DependencyValues.Continuation
|
||||||
|
private let database: DatabaseClient
|
||||||
|
|
||||||
init() {
|
init(
|
||||||
|
database: DatabaseClient
|
||||||
|
) {
|
||||||
self.values = withEscapedDependencies { $0 }
|
self.values = withEscapedDependencies { $0 }
|
||||||
|
self.database = database
|
||||||
}
|
}
|
||||||
|
|
||||||
func respond(to request: Request, chainingTo next: any AsyncResponder) async throws -> Response {
|
func respond(to request: Request, chainingTo next: any AsyncResponder) async throws -> Response {
|
||||||
try await values.yield {
|
try await values.yield {
|
||||||
try await withDependencies {
|
try await withDependencies {
|
||||||
$0.database = .live(database: request.db)
|
$0.database = database
|
||||||
$0.dateFormatter = .liveValue
|
$0.dateFormatter = .liveValue
|
||||||
} operation: {
|
} operation: {
|
||||||
try await next.respond(to: request)
|
try await next.respond(to: request)
|
||||||
|
|||||||
@@ -8,7 +8,10 @@ import Vapor
|
|||||||
@preconcurrency import VaporRouting
|
@preconcurrency import VaporRouting
|
||||||
|
|
||||||
// configures your application
|
// configures your application
|
||||||
public func configure(_ app: Application) async throws {
|
public func configure(
|
||||||
|
_ app: Application,
|
||||||
|
makeDatabaseClient: @escaping (any Database) -> DatabaseClient = { .live(database: $0) }
|
||||||
|
) async throws {
|
||||||
// cors middleware should come before default error middleware using `at: .beginning`
|
// cors middleware should come before default error middleware using `at: .beginning`
|
||||||
let corsConfiguration = CORSMiddleware.Configuration(
|
let corsConfiguration = CORSMiddleware.Configuration(
|
||||||
allowedOrigin: .all,
|
allowedOrigin: .all,
|
||||||
@@ -21,7 +24,6 @@ public func configure(_ app: Application) async throws {
|
|||||||
|
|
||||||
app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))
|
app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))
|
||||||
app.middleware.use(app.sessions.middleware)
|
app.middleware.use(app.sessions.middleware)
|
||||||
app.middleware.use(DependenciesMiddleware())
|
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
app.lifecycle.use(BrowserSyncHandler())
|
app.lifecycle.use(BrowserSyncHandler())
|
||||||
@@ -35,8 +37,13 @@ public func configure(_ app: Application) async throws {
|
|||||||
app.databases.use(DatabaseConfigurationFactory.sqlite(.memory), as: .sqlite)
|
app.databases.use(DatabaseConfigurationFactory.sqlite(.memory), as: .sqlite)
|
||||||
}
|
}
|
||||||
|
|
||||||
let databaseClient = DatabaseClient.live(database: app.db)
|
let databaseClient = makeDatabaseClient(app.db)
|
||||||
try await app.migrations.add(databaseClient.migrations())
|
|
||||||
|
if app.environment != .testing {
|
||||||
|
try await app.migrations.add(databaseClient.migrations())
|
||||||
|
}
|
||||||
|
|
||||||
|
app.middleware.use(DependenciesMiddleware(database: databaseClient))
|
||||||
|
|
||||||
app.mount(
|
app.mount(
|
||||||
SiteRoute.router,
|
SiteRoute.router,
|
||||||
@@ -50,7 +57,9 @@ public func configure(_ app: Application) async throws {
|
|||||||
use: siteHandler
|
use: siteHandler
|
||||||
)
|
)
|
||||||
|
|
||||||
try await app.autoMigrate()
|
if app.environment != .testing {
|
||||||
|
try await app.autoMigrate()
|
||||||
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
app.asyncCommands.use(SeedCommand(), as: "seed")
|
app.asyncCommands.use(SeedCommand(), as: "seed")
|
||||||
|
|||||||
@@ -10,3 +10,13 @@ public extension Snapshotting where Value == (any HTML), Format == String {
|
|||||||
return snapshotting
|
return snapshotting
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public extension Snapshotting where Value == String, Format == String {
|
||||||
|
static var html: Snapshotting {
|
||||||
|
var snapshotting = SimplySnapshotting.lines
|
||||||
|
.pullback { $0 }
|
||||||
|
|
||||||
|
snapshotting.pathExtension = "html"
|
||||||
|
return snapshotting
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -65,29 +65,6 @@ public extension Employee {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
//
|
|
||||||
// public extension Employee {
|
|
||||||
//
|
|
||||||
// static func generateMocks(count: Int = 10) -> [Self] {
|
|
||||||
// @Dependency(\.date.now) var now
|
|
||||||
// @Dependency(\.uuid) var uuid
|
|
||||||
//
|
|
||||||
// var output = [Self]()
|
|
||||||
//
|
|
||||||
// for _ in 0 ... count {
|
|
||||||
// output.append(.init(
|
|
||||||
// id: uuid(),
|
|
||||||
// active: Bool.random(),
|
|
||||||
// createdAt: now,
|
|
||||||
// firstName: RandomNames.firstNames.randomElement()!,
|
|
||||||
// lastName: RandomNames.lastNames.randomElement()!,
|
|
||||||
// updatedAt: now
|
|
||||||
// ))
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return output
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
public extension Employee.Create {
|
public extension Employee.Create {
|
||||||
|
|
||||||
@@ -103,13 +80,3 @@ public extension Employee {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// public extension Employee {
|
|
||||||
// static var mocks: [Self] {
|
|
||||||
// [
|
|
||||||
// .init(firstName: "Michael", lastName: "Housh"),
|
|
||||||
// .init(firstName: "Blob", lastName: "Esquire"),
|
|
||||||
// .init(firstName: "Testy", lastName: "McTestface")
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|||||||
@@ -43,29 +43,6 @@ public extension Vendor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
//
|
|
||||||
// public extension Vendor {
|
|
||||||
//
|
|
||||||
// static func generateMocks(count: Int = 20) -> [Self] {
|
|
||||||
// @Dependency(\.date.now) var now
|
|
||||||
// @Dependency(\.uuid) var uuid
|
|
||||||
//
|
|
||||||
// var output = [Self]()
|
|
||||||
//
|
|
||||||
// for _ in 0 ... count {
|
|
||||||
// output.append(.init(
|
|
||||||
// id: uuid(),
|
|
||||||
// name: RandomNames.companyNames.randomElement()!,
|
|
||||||
// branches: nil,
|
|
||||||
// createdAt: now,
|
|
||||||
// updatedAt: now
|
|
||||||
// ))
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return output
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
public extension Vendor.Create {
|
public extension Vendor.Create {
|
||||||
static func generateMocks(count: Int = 5) -> [Self] {
|
static func generateMocks(count: Int = 5) -> [Self] {
|
||||||
(0 ... count).reduce(into: [Self]()) { array, _ in
|
(0 ... count).reduce(into: [Self]()) { array, _ in
|
||||||
|
|||||||
188
Tests/AppTests/ViewSnapshotTests.swift
Normal file
188
Tests/AppTests/ViewSnapshotTests.swift
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
@testable import App
|
||||||
|
import DatabaseClient
|
||||||
|
import Dependencies
|
||||||
|
import HtmlSnapshotTesting
|
||||||
|
import SharedModels
|
||||||
|
import SnapshotTesting
|
||||||
|
import Vapor
|
||||||
|
import XCTVapor
|
||||||
|
|
||||||
|
final class ViewSnapshotTests: XCTestCase {
|
||||||
|
|
||||||
|
var app: Application!
|
||||||
|
let router = ViewRoute.router
|
||||||
|
|
||||||
|
override func setUp() {
|
||||||
|
app = Application(.testing)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func invokeTest() {
|
||||||
|
withSnapshotTesting(record: .missing) {
|
||||||
|
super.invokeTest()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tearDown() {
|
||||||
|
app.shutdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testEmployeeViews() async throws {
|
||||||
|
try await withDependencies {
|
||||||
|
$0.database.employees = .mock
|
||||||
|
} operation: {
|
||||||
|
@Dependency(\.database) var database
|
||||||
|
|
||||||
|
try await configure(app, makeDatabaseClient: { _ in database })
|
||||||
|
|
||||||
|
try await app.test(.GET, router.path(for: .employee(.index))) { res in
|
||||||
|
assertSnapshot(of: res.body.string, as: .html)
|
||||||
|
}
|
||||||
|
|
||||||
|
try await app.test(.GET, router.path(for: .employee(.form))) { res in
|
||||||
|
assertSnapshot(of: res.body.string, as: .html)
|
||||||
|
}
|
||||||
|
|
||||||
|
for context in SharedModels.ViewRoute.SelectContext.allCases {
|
||||||
|
try app.test(.GET, router.path(for: .employee(.select(context: context)))) { res in
|
||||||
|
assertSnapshot(of: res.body.string, as: .html)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try app.test(.GET, router.path(for: .employee(.get(id: UUID(0))))) { res in
|
||||||
|
assertSnapshot(of: res.body.string, as: .html)
|
||||||
|
}
|
||||||
|
|
||||||
|
try app.test(.POST, router.path(for: .employee(.index)), beforeRequest: { req in
|
||||||
|
req.body = ByteBuffer(string: "firstName=Testy&lastName=McTestface")
|
||||||
|
}, afterResponse: { res in
|
||||||
|
assertSnapshot(of: res.body.string, as: .html)
|
||||||
|
})
|
||||||
|
|
||||||
|
try app.test(.PUT, router.path(for: .employee(.update(id: UUID(0), updates: .mock))), beforeRequest: { req in
|
||||||
|
req.body = ByteBuffer(string: "firstName=Testy&lastName=McTestface")
|
||||||
|
}, afterResponse: { res in
|
||||||
|
assertSnapshot(of: res.body.string, as: .html)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: These need to come after mocks are generated.
|
||||||
|
// func testPurchaseOrderIndex() async throws {
|
||||||
|
// try await configure(app)
|
||||||
|
// try await app.test(.GET, router.path(for: .purchaseOrder(.index))) { res in
|
||||||
|
// assertSnapshot(of: res.body.string, as: .html)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DatabaseClient.Employees {
|
||||||
|
static var mock: Self {
|
||||||
|
.init(
|
||||||
|
create: { _ in .mock },
|
||||||
|
delete: { _ in },
|
||||||
|
fetchAll: { _ in [Employee.mock] },
|
||||||
|
get: { _ in Employee.mock },
|
||||||
|
update: { _, _ in Employee.mock }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Date {
|
||||||
|
static var mock: Self {
|
||||||
|
Date(timeIntervalSince1970: 1_234_567_890)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Employee {
|
||||||
|
static var mock: Self {
|
||||||
|
Employee(
|
||||||
|
id: UUID(0),
|
||||||
|
createdAt: Date(timeIntervalSince1970: 1_234_567_890),
|
||||||
|
firstName: "Testy",
|
||||||
|
lastName: "McTestface",
|
||||||
|
updatedAt: Date(timeIntervalSince1970: 1_234_567_890)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Employee.Create {
|
||||||
|
static var mock: Self {
|
||||||
|
.init(firstName: "Testy", lastName: "McTestface")
|
||||||
|
}
|
||||||
|
|
||||||
|
func employeeMock() -> Employee {
|
||||||
|
@Dependency(\.date.now) var now
|
||||||
|
return .init(
|
||||||
|
id: UUID(0),
|
||||||
|
createdAt: Date(timeIntervalSince1970: 1_234_567_890),
|
||||||
|
firstName: firstName,
|
||||||
|
lastName: lastName,
|
||||||
|
updatedAt: Date(timeIntervalSince1970: 1_234_567_890)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Employee.Update {
|
||||||
|
static var mock: Self {
|
||||||
|
.init(firstName: "Testy", lastName: "McTestface", active: false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension User {
|
||||||
|
static var mock: Self {
|
||||||
|
.init(id: UUID(0), email: "test@example.com", username: "test")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension User.Create {
|
||||||
|
static var mock: Self {
|
||||||
|
.init(username: "test", email: "test@example.com", password: "super-secret", confirmPassword: "super-secret")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Vendor {
|
||||||
|
static var mock: Self {
|
||||||
|
.init(id: UUID(0), name: "Test", branches: nil, createdAt: .mock, updatedAt: .mock)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Vendor.Create {
|
||||||
|
static var mock: Self {
|
||||||
|
.init(name: "Test")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension VendorBranch {
|
||||||
|
static var mock: Self {
|
||||||
|
.init(id: UUID(1), name: "Mock", vendorID: UUID(0), createdAt: .mock, updatedAt: .mock)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension VendorBranch.Create {
|
||||||
|
static var mock: Self {
|
||||||
|
.init(name: "Mock", vendorID: UUID(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension VendorBranch.Detail {
|
||||||
|
static var mock: Self {
|
||||||
|
.init(id: UUID(1), name: "Mock", vendor: .mock, createdAt: .mock, updatedAt: .mock)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension PurchaseOrder {
|
||||||
|
static var mock: Self {
|
||||||
|
.init(
|
||||||
|
id: 1,
|
||||||
|
workOrder: 12245,
|
||||||
|
materials: "foo",
|
||||||
|
customer: "Testy McTestface",
|
||||||
|
truckStock: true,
|
||||||
|
createdBy: .mock,
|
||||||
|
createdFor: .mock,
|
||||||
|
vendorBranch: .mock,
|
||||||
|
createdAt: .mock,
|
||||||
|
updatedAt: .mock
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<tr id="employee-00000000-0000-0000-0000-000000000000"><td>Testy Mctestface</td><td><button class="btn-detail" style="padding-left: 15px;" hx-get="/employees/00000000-0000-0000-0000-000000000000" hx-target="#float" hx-push-url="true" hx-swap="outerHTML transition:true swap:0.5s">〉</button></td></tr>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<!DOCTYPE html><html lang="en"><head><title>Purchase Orders</title><meta charset="UTF-8"><script src="https://unpkg.com/htmx.org@2.0.4"></script><script src="/js/main.js"></script><link rel="stylesheet" href="/css/main.css"><link rel="icon" href="/images/favicon.ico" type="image/x-icon"></head><body><header class="header"><div id="logo">HHE - Purchase Orders</div><div class="sidepanel" id="sidepanel"><a href="javascript:void(0)" class="closebtn" onclick="closeSidepanel()">x</a><a hx-get="/purchase-orders?page=1&limit=50" hx-target="body" hx-push-url="true">Purchase Orders</a><a hx-get="/users" hx-target="body" hx-push-url="true">Users</a><a hx-get="/employees" hx-target="body" hx-push-url="true">Employees</a><a hx-get="/vendors" hx-target="body" hx-push-url="true">Vendors</a><div style="border-bottom: 1px solid grey; margin-bottom: 5px;"></div><a hx-post="/logout" hx-target="#content" hx-swap="outerHTML" hx-trigger="click">Logout</a></div><button class="openbtn" onclick="openSidepanel()"><img src="/images/menu.svg" style="width: 30px;, height: 30px;"></button></header><div class="container" style="padding: 20px 20px;"><h1>Employees</h1><br><p class="secondary"><i>Employees are who purchase orders can be issued to.</i></p><br></div><div class="container"><div id="float" class="float" style="display: block;"><div class="btn-row"><button class="btn-close" onclick="toggleContent('float'); window.location.href='/employees';">x</button></div><form hx-post="/employees" hx-target="#employee-table" hx-swap="beforeend transition:true swap:0.5s" hx-on::after-request="if(event.detail.successful) toggleContent('float'); window.location.href='/employees';"><div class="row"><input type="text" class="col-5" name="firstName" value="" placeholder="First Name" required><div class="col-2"></div><input type="text" class="col-5" name="lastName" value="" placeholder="Last Name" required></div><div class="btn-row"><button type="submit" class="btn-primary">Create</button></div></form></div><table><thead><tr><th>Name</th><th style="width: 100px;"><button class="btn btn-add" style="padding: 0px 10px;" hx-get="/employees/create" hx-target="#float" hx-swap="outerHTML transition:true swap:0.5s">+</button></th></tr></thead><tbody id="employee-table"><tr id="employee-00000000-0000-0000-0000-000000000000"><td>Testy Mctestface</td><td><button class="btn-detail" style="padding-left: 15px;" hx-get="/employees/00000000-0000-0000-0000-000000000000" hx-target="#float" hx-push-url="true" hx-swap="outerHTML transition:true swap:0.5s">〉</button></td></tr></tbody></table></div></body></html>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<!DOCTYPE html><html lang="en"><head><title>Purchase Orders</title><meta charset="UTF-8"><script src="https://unpkg.com/htmx.org@2.0.4"></script><script src="/js/main.js"></script><link rel="stylesheet" href="/css/main.css"><link rel="icon" href="/images/favicon.ico" type="image/x-icon"></head><body><header class="header"><div id="logo">HHE - Purchase Orders</div><div class="sidepanel" id="sidepanel"><a href="javascript:void(0)" class="closebtn" onclick="closeSidepanel()">x</a><a hx-get="/purchase-orders?page=1&limit=50" hx-target="body" hx-push-url="true">Purchase Orders</a><a hx-get="/users" hx-target="body" hx-push-url="true">Users</a><a hx-get="/employees" hx-target="body" hx-push-url="true">Employees</a><a hx-get="/vendors" hx-target="body" hx-push-url="true">Vendors</a><div style="border-bottom: 1px solid grey; margin-bottom: 5px;"></div><a hx-post="/logout" hx-target="#content" hx-swap="outerHTML" hx-trigger="click">Logout</a></div><button class="openbtn" onclick="openSidepanel()"><img src="/images/menu.svg" style="width: 30px;, height: 30px;"></button></header><div class="container" style="padding: 20px 20px;"><h1>Employees</h1><br><p class="secondary"><i>Employees are who purchase orders can be issued to.</i></p><br></div><div class="container"><div id="float" class="float" style="display: block;"><div class="btn-row"><button class="btn-close" onclick="toggleContent('float'); window.location.href='/employees';">x</button></div><form hx-put="/employees/00000000-0000-0000-0000-000000000000" hx-target="#employee-00000000-0000-0000-0000-000000000000" hx-swap="outerHTML transition:true swap:0.5s" hx-on::after-request="if(event.detail.successful) toggleContent('float'); window.location.href='/employees';"><div class="row"><input type="text" class="col-5" name="firstName" value="Testy" placeholder="First Name" required><div class="col-2"></div><input type="text" class="col-5" name="lastName" value="McTestface" placeholder="Last Name" required></div><div class="btn-row"><button type="submit" class="btn-primary">Update</button><button class="danger" hx-confirm="Are you sure you want to delete this employee?" hx-delete="/employees/00000000-0000-0000-0000-000000000000" hx-target="#employee-00000000-0000-0000-0000-000000000000" hx-swap="outerHTML transition:true swap:1s">Delete</button></div></form></div><table><thead><tr><th>Name</th><th style="width: 100px;"><button class="btn btn-add" style="padding: 0px 10px;" hx-get="/employees/create" hx-target="#float" hx-swap="outerHTML transition:true swap:0.5s">+</button></th></tr></thead><tbody id="employee-table"><tr id="employee-00000000-0000-0000-0000-000000000000"><td>Testy Mctestface</td><td><button class="btn-detail" style="padding-left: 15px;" hx-get="/employees/00000000-0000-0000-0000-000000000000" hx-target="#float" hx-push-url="true" hx-swap="outerHTML transition:true swap:0.5s">〉</button></td></tr></tbody></table></div></body></html>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<!DOCTYPE html><html lang="en"><head><title>Purchase Orders</title><meta charset="UTF-8"><script src="https://unpkg.com/htmx.org@2.0.4"></script><script src="/js/main.js"></script><link rel="stylesheet" href="/css/main.css"><link rel="icon" href="/images/favicon.ico" type="image/x-icon"></head><body><header class="header"><div id="logo">HHE - Purchase Orders</div><div class="sidepanel" id="sidepanel"><a href="javascript:void(0)" class="closebtn" onclick="closeSidepanel()">x</a><a hx-get="/purchase-orders?page=1&limit=50" hx-target="body" hx-push-url="true">Purchase Orders</a><a hx-get="/users" hx-target="body" hx-push-url="true">Users</a><a hx-get="/employees" hx-target="body" hx-push-url="true">Employees</a><a hx-get="/vendors" hx-target="body" hx-push-url="true">Vendors</a><div style="border-bottom: 1px solid grey; margin-bottom: 5px;"></div><a hx-post="/logout" hx-target="#content" hx-swap="outerHTML" hx-trigger="click">Logout</a></div><button class="openbtn" onclick="openSidepanel()"><img src="/images/menu.svg" style="width: 30px;, height: 30px;"></button></header><div class="container" style="padding: 20px 20px;"><h1>Employees</h1><br><p class="secondary"><i>Employees are who purchase orders can be issued to.</i></p><br></div><div class="container"><div id="float" class="" style="display: hidden;"></div><table><thead><tr><th>Name</th><th style="width: 100px;"><button class="btn btn-add" style="padding: 0px 10px;" hx-get="/employees/create" hx-target="#float" hx-swap="outerHTML transition:true swap:0.5s">+</button></th></tr></thead><tbody id="employee-table"><tr id="employee-00000000-0000-0000-0000-000000000000"><td>Testy Mctestface</td><td><button class="btn-detail" style="padding-left: 15px;" hx-get="/employees/00000000-0000-0000-0000-000000000000" hx-target="#float" hx-push-url="true" hx-swap="outerHTML transition:true swap:0.5s">〉</button></td></tr></tbody></table></div></body></html>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<select name="createdForID" class="col-3"><option value="00000000-0000-0000-0000-000000000000">Testy Mctestface</option></select>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<select name="createdForID" class="col-6" style="margin-left: 15px;"><option value="00000000-0000-0000-0000-000000000000">Testy Mctestface</option></select>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<tr id="employee-00000000-0000-0000-0000-000000000000"><td>Testy Mctestface</td><td><button class="btn-detail" style="padding-left: 15px;" hx-get="/employees/00000000-0000-0000-0000-000000000000" hx-target="#float" hx-push-url="true" hx-swap="outerHTML transition:true swap:0.5s">〉</button></td></tr>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<!DOCTYPE html><html lang="en"><head><title>Purchase Orders</title><meta charset="UTF-8"><script src="https://unpkg.com/htmx.org@2.0.4"></script><script src="/js/main.js"></script><link rel="stylesheet" href="/css/main.css"><link rel="icon" href="/images/favicon.ico" type="image/x-icon"></head><body><header class="header"><div id="logo">HHE - Purchase Orders</div><div class="sidepanel" id="sidepanel"><a href="javascript:void(0)" class="closebtn" onclick="closeSidepanel()">x</a><a hx-get="/purchase-orders?page=1&limit=50" hx-target="body" hx-push-url="true">Purchase Orders</a><a hx-get="/users" hx-target="body" hx-push-url="true">Users</a><a hx-get="/employees" hx-target="body" hx-push-url="true">Employees</a><a hx-get="/vendors" hx-target="body" hx-push-url="true">Vendors</a><div style="border-bottom: 1px solid grey; margin-bottom: 5px;"></div><a hx-post="/logout" hx-target="#content" hx-swap="outerHTML" hx-trigger="click">Logout</a></div><button class="openbtn" onclick="openSidepanel()"><img src="/images/menu.svg" style="width: 30px;, height: 30px;"></button></header><div class="container" style="padding: 20px 20px;"><h1>Employees</h1><br><p class="secondary"><i>Employees are who purchase orders can be issued to.</i></p><br></div><div class="container"><div id="float" class="" style="display: hidden;"></div><table><thead><tr><th>Name</th><th style="width: 100px;"><button class="btn btn-add" style="padding: 0px 10px;" hx-get="/employees/create" hx-target="#float" hx-swap="outerHTML transition:true swap:0.5s">+</button></th></tr></thead><tbody id="employee-table"><tr id="employee-00000000-0000-0000-0000-000000000000"><td>Testy Mctestface</td><td><button class="btn-detail" style="padding-left: 15px;" hx-get="/employees/00000000-0000-0000-0000-000000000000" hx-target="#float" hx-push-url="true" hx-swap="outerHTML transition:true swap:0.5s">〉</button></td></tr></tbody></table></div></body></html>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<!DOCTYPE html><html lang="en"><head><title>Purchase Orders</title><meta charset="UTF-8"><script src="https://unpkg.com/htmx.org@2.0.4"></script><script src="/js/main.js"></script><link rel="stylesheet" href="/css/main.css"><link rel="icon" href="/images/favicon.ico" type="image/x-icon"></head><body><header class="header"><div id="logo">HHE - Purchase Orders</div><div class="sidepanel" id="sidepanel"><a href="javascript:void(0)" class="closebtn" onclick="closeSidepanel()">x</a><a hx-get="/purchase-orders?page=1&limit=50" hx-target="body" hx-push-url="true">Purchase Orders</a><a hx-get="/users" hx-target="body" hx-push-url="true">Users</a><a hx-get="/employees" hx-target="body" hx-push-url="true">Employees</a><a hx-get="/vendors" hx-target="body" hx-push-url="true">Vendors</a><div style="border-bottom: 1px solid grey; margin-bottom: 5px;"></div><a hx-post="/logout" hx-target="#content" hx-swap="outerHTML" hx-trigger="click">Logout</a></div><button class="openbtn" onclick="openSidepanel()"><img src="/images/menu.svg" style="width: 30px;, height: 30px;"></button></header><div class="container" style="padding: 20px 20px;"><h1>Employees</h1><br><p class="secondary"><i>Employees are who purchase orders can be issued to.</i></p><br></div><div class="container"><div id="float" class="float" style="display: block;"><div class="btn-row"><button class="btn-close" onclick="toggleContent('float'); window.location.href='/employees';">x</button></div><form hx-post="/employees" hx-target="#employee-table" hx-swap="beforeend transition:true swap:0.5s" hx-on::after-request="if(event.detail.successful) toggleContent('float'); window.location.href='/employees';"><div class="row"><input type="text" class="col-5" name="firstName" value="" placeholder="First Name" required><div class="col-2"></div><input type="text" class="col-5" name="lastName" value="" placeholder="Last Name" required></div><div class="btn-row"><button type="submit" class="btn-primary">Create</button></div></form></div><table><thead><tr><th>Name</th><th style="width: 100px;"><button class="btn btn-add" style="padding: 0px 10px;" hx-get="/employees/create" hx-target="#float" hx-swap="outerHTML transition:true swap:0.5s">+</button></th></tr></thead><tbody id="employee-table"><tr id="employee-00000000-0000-0000-0000-000000000000"><td>Testy Mctestface</td><td><button class="btn-detail" style="padding-left: 15px;" hx-get="/employees/00000000-0000-0000-0000-000000000000" hx-target="#float" hx-push-url="true" hx-swap="outerHTML transition:true swap:0.5s">〉</button></td></tr></tbody></table></div></body></html>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<select name="createdForID" class="col-3"><option value="00000000-0000-0000-0000-000000000000">Testy Mctestface</option></select>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<select name="createdForID" class="col-6" style="margin-left: 15px;"><option value="00000000-0000-0000-0000-000000000000">Testy Mctestface</option></select>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<!DOCTYPE html><html lang="en"><head><title>Purchase Orders</title><meta charset="UTF-8"><script src="https://unpkg.com/htmx.org@2.0.4"></script><script src="/js/main.js"></script><link rel="stylesheet" href="/css/main.css"><link rel="icon" href="/images/favicon.ico" type="image/x-icon"></head><body><header class="header"><div id="logo">HHE - Purchase Orders</div><div class="sidepanel" id="sidepanel"><a href="javascript:void(0)" class="closebtn" onclick="closeSidepanel()">x</a><a hx-get="/purchase-orders?page=1&limit=50" hx-target="body" hx-push-url="true">Purchase Orders</a><a hx-get="/users" hx-target="body" hx-push-url="true">Users</a><a hx-get="/employees" hx-target="body" hx-push-url="true">Employees</a><a hx-get="/vendors" hx-target="body" hx-push-url="true">Vendors</a><div style="border-bottom: 1px solid grey; margin-bottom: 5px;"></div><a hx-post="/logout" hx-target="#content" hx-swap="outerHTML" hx-trigger="click">Logout</a></div><button class="openbtn" onclick="openSidepanel()"><img src="/images/menu.svg" style="width: 30px;, height: 30px;"></button></header><div class="container" style="padding: 20px 20px;"><h1>Employees</h1><br><p class="secondary"><i>Employees are who purchase orders can be issued to.</i></p><br></div><div class="container"><div id="float" class="float" style="display: block;"><div class="btn-row"><button class="btn-close" onclick="toggleContent('float'); window.location.href='/employees';">x</button></div><form hx-put="/employees/00000000-0000-0000-0000-000000000000" hx-target="#employee-00000000-0000-0000-0000-000000000000" hx-swap="outerHTML transition:true swap:0.5s" hx-on::after-request="if(event.detail.successful) toggleContent('float'); window.location.href='/employees';"><div class="row"><input type="text" class="col-5" name="firstName" value="Testy" placeholder="First Name" required><div class="col-2"></div><input type="text" class="col-5" name="lastName" value="McTestface" placeholder="Last Name" required></div><div class="btn-row"><button type="submit" class="btn-primary">Update</button><button class="danger" hx-confirm="Are you sure you want to delete this employee?" hx-delete="/employees/00000000-0000-0000-0000-000000000000" hx-target="#employee-00000000-0000-0000-0000-000000000000" hx-swap="outerHTML transition:true swap:1s">Delete</button></div></form></div><table><thead><tr><th>Name</th><th style="width: 100px;"><button class="btn btn-add" style="padding: 0px 10px;" hx-get="/employees/create" hx-target="#float" hx-swap="outerHTML transition:true swap:0.5s">+</button></th></tr></thead><tbody id="employee-table"><tr id="employee-00000000-0000-0000-0000-000000000000"><td>Testy Mctestface</td><td><button class="btn-detail" style="padding-left: 15px;" hx-get="/employees/00000000-0000-0000-0000-000000000000" hx-target="#float" hx-push-url="true" hx-swap="outerHTML transition:true swap:0.5s">〉</button></td></tr></tbody></table></div></body></html>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<tr id="employee-00000000-0000-0000-0000-000000000000"><td>Testy Mctestface</td><td><button class="btn-detail" style="padding-left: 15px;" hx-get="/employees/00000000-0000-0000-0000-000000000000" hx-target="#float" hx-push-url="true" hx-swap="outerHTML transition:true swap:0.5s">〉</button></td></tr>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<tr id="employee-00000000-0000-0000-0000-000000000000"><td>Testy Mctestface</td><td><button class="btn-detail" style="padding-left: 15px;" hx-get="/employees/00000000-0000-0000-0000-000000000000" hx-target="#float" hx-push-url="true" hx-swap="outerHTML transition:true swap:0.5s">〉</button></td></tr>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<!DOCTYPE html><html lang="en"><head><title>Purchase Orders</title><meta charset="UTF-8"><script src="https://unpkg.com/htmx.org@2.0.4"></script><script src="/js/main.js"></script><link rel="stylesheet" href="/css/main.css"><link rel="icon" href="/images/favicon.ico" type="image/x-icon"></head><body><header class="header"><div id="logo">HHE - Purchase Orders</div><div class="sidepanel" id="sidepanel"><a href="javascript:void(0)" class="closebtn" onclick="closeSidepanel()">x</a><a hx-get="/purchase-orders?page=1&limit=50" hx-target="body" hx-push-url="true">Purchase Orders</a><a hx-get="/users" hx-target="body" hx-push-url="true">Users</a><a hx-get="/employees" hx-target="body" hx-push-url="true">Employees</a><a hx-get="/vendors" hx-target="body" hx-push-url="true">Vendors</a><div style="border-bottom: 1px solid grey; margin-bottom: 5px;"></div><a hx-post="/logout" hx-target="#content" hx-swap="outerHTML" hx-trigger="click">Logout</a></div><button class="openbtn" onclick="openSidepanel()"><img src="/images/menu.svg" style="width: 30px;, height: 30px;"></button></header><div class="container" style="padding: 20px 20px;"><h1>Purchase Orders</h1><br><p class="secondary"><i></i></p><br></div><div class="container" id="purchase-order-content"><div id="float" class="" style="display: hidden;"></div><table id="purchase-order"><thead><tr><div class="btn-row"><button id="btn-search" class="btn-primary" style="position: absolute; top: 80px; right: 20px;" hx-get="/purchase-orders/search?table=true" hx-target="body" hx-swap="outerHTML transition:true swap:0.5s" hx-push-url="true"><img src="/images/search.svg" width="30" height="30"></button></div></tr><tr><th>PO</th><th>Work Order</th><th>Customer</th><th>Vendor</th><th>Materials</th><th>Created For</th><th><button class="btn btn-add" hx-get="/purchase-orders/create" hx-target="#float" hx-swap="outerHTML" hx-push-url="true">+</button></th></tr></thead><tbody id="purchase-order-table"></tbody></table></div></body></html>
|
||||||
Reference in New Issue
Block a user