Merge pull request #7 from dredgy/installer

Migration system added.
This commit is contained in:
dredgy
2022-02-26 22:24:07 +10:00
committed by GitHub
122 changed files with 774 additions and 148 deletions

View File

@@ -11,10 +11,10 @@ let getClerkByLoginCode (loginCode: int) =
let clerk =
select {
table "clerks"
where (eq "clerk_login_code" loginCode)
where (eq "login_code" loginCode)
take 1
}
|> db.Select<clerk>
|> Database.Select<clerk>
|> EnumerableToArray
if (clerk |> length) > 0 then
@@ -26,19 +26,19 @@ let deleteSession sessionId context =
delete {
table "sessions"
where (eq "session_id" sessionId)
} |> db.Delete |> ignore
} |> Database.Delete |> ignore
Browser.deleteCookie "dredgepos_clerk_logged_in" context
let deleteSessionByClerkId clerk_id context =
delete {
table "sessions"
where (eq "clerk_id" clerk_id)
} |> db.Delete |> ignore
} |> Database.Delete |> ignore
Browser.deleteCookie "dredgepos_clerk_logged_in" context
let createNewSession (clerk: clerk) context =
if (getClerkByLoginCode clerk.clerk_login_code).IsSome then
if (getClerkByLoginCode clerk.login_code).IsSome then
deleteSessionByClerkId clerk.id context
let newSessionId = (Guid.NewGuid().ToString "N") + (Guid.NewGuid().ToString "N")
@@ -53,18 +53,14 @@ let createNewSession (clerk: clerk) context =
table "sessions"
value newSession
}
|> db.Insert
|> Database.Insert
|> ignore
Browser.setCookie "dredgepos_clerk_logged_in" newSessionId (DateTimeOffset.UtcNow.AddHours(24.0)) context
let sessionExists (sessionId: string) context =
let sessions =
select {
table "sessions"
where (eq "session_id" sessionId)
} |> db.Select<session>
let sessions = Entity.GetAllByColumn<session> "session_id" sessionId
match sessions |> length with
| 0 -> false
@@ -78,11 +74,11 @@ let sessionExists (sessionId: string) context =
false
let checkAuthentication clerk =
let existingClerk = getClerkByLoginCode clerk.clerk_login_code
let existingClerk = getClerkByLoginCode clerk.login_code
existingClerk.IsSome
&& existingClerk.Value.id = clerk.id
&& existingClerk.Value.clerk_name = clerk.clerk_name
&& existingClerk.Value.clerk_login_code = clerk.clerk_login_code
&& existingClerk.Value.name = clerk.name
&& existingClerk.Value.login_code = clerk.login_code
let getLoginCookie context = Browser.getCookie "dredgepos_clerk_logged_in" context
@@ -91,7 +87,7 @@ let getSession (sessionId: string) =
select {
table "sessions"
where (eq "session_id" sessionId)
} |> db.Select<session>
} |> Database.Select<session>
match sessions |> length with
| 0 -> {session_id = ""; clerk_json = ""; clerk_id= 0; expires= 0; id=0}
@@ -99,7 +95,7 @@ let getSession (sessionId: string) =
let getCurrentClerk context =
let cookie = getLoginCookie context
let emptyClerk = {id=0; clerk_login_code=0; clerk_usergroup=0; clerk_name=""}
let emptyClerk = {id=0; login_code=0; user_group_id=0; name=""}
match cookie with
| "" ->
Browser.redirect "/login" context

View File

@@ -1,46 +1,98 @@
module db
module Database
open Dapper
open Dapper.FSharp
open Dapper.FSharp.PostgreSQL
open DredgeFramework
open DredgePos.Types
open Npgsql
let connString = "Server=localhost;Port=5432;User Id=postgres;Password=root;Database=dredgepos;Include Error Detail=true"
//let connString = "server=localhost;uid=root;pwd=;database=dredgepos;table cache = false"
let connection = new Npgsql.NpgsqlConnection(connString)
let connect connectionString = new NpgsqlConnection(connectionString)
let getDatabaseSettings () = (getConfig ()).database
let getConnectionString () =
let db = getDatabaseSettings ()
$"Server={db.host};Port={db.port};User Id={db.username};Password={db.password};Database={db.db_name};Include Error Detail=true"
let connectToDatabase () = connect (getConnectionString ())
let closeAndReturn (connection: NpgsqlConnection) (result: 'a) =
connection.Dispose()
result
let Select<'a> asyncQuery =
let connection = connectToDatabase ()
asyncQuery
|> connection.SelectAsync<'a>
|> RunSynchronously
|> EnumerableToArray
|> closeAndReturn connection
let SelectJoin<'a, 'b> asyncQuery =
let connection = connectToDatabase ()
asyncQuery
|> connection.SelectAsync<'a, 'b>
|> RunSynchronously
|> EnumerableToArray
|> closeAndReturn connection
let Insert<'a> asyncQuery =
let connection = connectToDatabase ()
asyncQuery
|> connection.InsertAsync<'a>
|> RunSynchronously
|> closeAndReturn connection
let InsertOutput<'a> asyncQuery =
let connection = connectToDatabase ()
asyncQuery
|> connection.InsertOutputAsync<'a, 'a>
|> RunSynchronously
|> EnumerableToArray
|> closeAndReturn connection
let Update<'a> asyncQuery =
let connection = connectToDatabase ()
asyncQuery
|> connection.UpdateOutputAsync<'a, 'a>
|> RunSynchronously
|> EnumerableToArray
|> closeAndReturn connection
let Delete<'a> asyncQuery =
let connection = connectToDatabase ()
asyncQuery
|> connection.DeleteAsync
|> RunSynchronously
|> RunSynchronously
|> closeAndReturn connection
let NonDbSpecificQuery (sql: string) (connection: NpgsqlConnection) =
sql
|> fun str -> System.IO.File.WriteAllText("sql.log", str); str
|> connection.Execute
|> closeAndReturn connection
let rawQuery (sql: string) = connectToDatabase () |> NonDbSpecificQuery sql
let CreateTable (tableName: string) (columnList: (string * string) list) =
let columns =
columnList
|> List.filter (fun (columnName, _) -> columnName <> "id")
|> List.map (fun (columnName, columnType) -> $""" "{columnName}" {columnType} not null""")
|> String.concat ",\n\t\t\t"
$"""
create table if not exists {tableName}
(
id serial
constraint {tableName}_pk
primary key,
{columns}
);
"""
|> fun str -> System.IO.File.WriteAllText("sql.log", str); str
|> rawQuery
|> ignore

View File

@@ -7,8 +7,8 @@ open System.Drawing
open System.IO
open System.Linq
open System.Xml;
open System.Xml.XPath;
open System.Xml.Xsl
open DredgePos.Types
open FSharp.Reflection
open Thoth.Json.Net
@@ -100,4 +100,14 @@ let GetImageSize image =
let loadedImage = loadImage image
loadedImage.Width, loadedImage.Height
let CurrentTime() = DateTimeOffset.Now.ToUnixTimeSeconds() |> int
let CurrentTime() = DateTimeOffset.Now.ToUnixTimeSeconds() |> int
let getConfig () =
"config.json"
|> GetFileContents
|> Decode.Auto.fromString<config>
|> (fun result ->
match result with
| Ok config -> config
| Error message -> failwith ("config.json is not valid :" + message)
)

View File

@@ -1,4 +1,5 @@
module Entity
open Dapper
open Dapper.FSharp
open DredgeFramework
open Pluralize.NET.Core
@@ -15,7 +16,7 @@ let Create (record: 'x)=
value record
excludeColumn "id"
}
|> db.InsertOutput
|> Database.InsertOutput
|> first
@@ -28,7 +29,7 @@ let inline Update (record: ^x) =
where (eq "id" id)
excludeColumn "id"
}
|> db.Update
|> Database.Update
let GetAll<'x> =
let tableName = GetDatabaseTable<'x>
@@ -36,7 +37,7 @@ let GetAll<'x> =
select {
table tableName
}
|> db.Select<'x>
|> Database.Select<'x>
let GetAllByColumn<'x> (column: string) (value: obj) =
let tableName = GetDatabaseTable<'x>
@@ -44,7 +45,9 @@ let GetAllByColumn<'x> (column: string) (value: obj) =
select {
table tableName
where (eq column value)
} |> db.Select<'x>
} |> Database.Select<'x>
let GetFirstByColumn<'x> (column: string) (value: obj) = (GetAllByColumn<'x> column value) |> first
let GetAllInVenue<'x> = GetAllByColumn<'x> "venue_id" (getCurrentVenue ())
let GetById<'x> (id: int) = GetAllByColumn<'x> "id" id |> first
@@ -67,7 +70,7 @@ let DeleteById<'x> id =
delete {
table tableName
where (eq "id" id)
} |> db.Delete |> ignore
} |> Database.Delete |> ignore
entity

View File

@@ -13,7 +13,7 @@ type reservation = {
[<CLIMutable>]
type venue = {
id: int
venue_name: string
name: string
}
[<CLIMutable>]
@@ -38,7 +38,7 @@ type floorplan_table = {
type print_group = {
id: int
name: string
printer: int
printer_id: int
venue_id: int
}
@@ -47,14 +47,14 @@ type sales_category = {
id: int
parent: int
name: string
print_group: int
print_group_id: int
venue_id: int
}
[<CLIMutable>]
type floorplan_room = {
type room = {
id: int
room_name: string
name: string
background_image: string
venue_id: int
}
@@ -62,18 +62,23 @@ type floorplan_room = {
[<CLIMutable>]
type floorplan_decoration = {
id: int
decoration_room: int
decoration_pos_x: int
decoration_pos_y: int
decoration_rotation: int
decoration_width: int
decoration_height: int
decoration_image: string
room_id: int
pos_x: int
pos_y: int
rotation: int
width: int
height: int
image: string
venue_id: int
}
[<CLIMutable>]
type clerk = {id: int; clerk_name: string; clerk_login_code: int; clerk_usergroup: int}
type clerk = {
id: int
name: string
login_code: int
user_group_id: int
}
[<CLIMutable>]
type session = {id: int; session_id: string; clerk_json: string; clerk_id: int; expires: int}
@@ -82,7 +87,7 @@ type session = {id: int; session_id: string; clerk_json: string; clerk_id: int;
type order_screen_page_group = {id: int; order: int; venue_id: int; label: string; grid_id: int}
[<CLIMutable>]
type grid = {id: int; grid_name: string; grid_rows: int; grid_cols: int; grid_data: string}
type grid = {id: int; name: string; rows: int; cols: int; data: string}
[<CLIMutable>]
type button = {
@@ -100,13 +105,30 @@ type button = {
[<CLIMutable>]
type item = {
id: int
item_code: string
item_category: int
item_name: string
code: string
sales_category_id: int
name: string
item_type: string
price1: int
price2: int
price3: int
price4: int
price5: int
}
[<CLIMutable>]
type db_config = {
db_name: string
username: string
password: string
host: string
port: int
}
[<CLIMutable>]
type config = {
database: db_config
}
[<CLIMutable>]
type migration = {
id: int
name: string
timestamp: int
}

View File

@@ -26,6 +26,11 @@
<Compile Include="Authenticate\Router.fs" />
<Compile Include="Ajax\Controller.fs" />
<Compile Include="Ajax\Router.fs" />
<Compile Include="Migrations\CreateDatabaseSchema.fs" />
<Compile Include="Migrations\PopulateTestData.fs" />
<Compile Include="Installer\Model.fs" />
<Compile Include="Installer\Controller.fs" />
<Compile Include="Installer\Router.fs" />
<Compile Include="Floorplan\Model.fs" />
<Compile Include="Floorplan\View.fs" />
<Compile Include="Floorplan\Controller.fs" />

View File

@@ -10,10 +10,10 @@ open Microsoft.AspNetCore.Http
open Model
open System.IO
let makeRoomButton (room: floorplan_room) =
let makeRoomButton (room: room) =
let vars = map [
"roomId", room.id |> string
"roomName", room.room_name
"roomName", room.name
]
Theme.loadTemplateWithVars "roomButton" vars
@@ -50,7 +50,7 @@ let getFloorplanData (id: int) =
tables = tableList
decorations = Entity.GetAllInVenue<floorplan_decoration>
activeTableNumbers = Model.getActiveTables (getCurrentVenue())
rooms = Entity.GetAllInVenue<floorplan_room>
rooms = Entity.GetAllInVenue<room>
reservations = reservationList
|}
|> ajaxSuccess
@@ -78,19 +78,19 @@ let transferTable (origin, destination) =
ajaxSuccess data |> json
let AddDecoration (data: floorplan_decoration) =
let image = "wwwroot/images/decorations/" + data.decoration_image
let image = "wwwroot/images/decorations/" + data.image
let width, height = image |> GetImageSize
let aspectRatio = decimal width / decimal height
let decoration : floorplan_decoration = {
id = 0
decoration_height = (200m / aspectRatio) |> int
decoration_width = 200
decoration_rotation = 0
decoration_image = data.decoration_image
decoration_pos_x = data.decoration_pos_x
decoration_pos_y = data.decoration_pos_y
decoration_room = data.decoration_room
height = (200m / aspectRatio) |> int
width = 200
rotation = 0
image = data.image
pos_x = data.pos_x
pos_y = data.pos_y
room_id = data.room_id
venue_id = data.venue_id
}
@@ -110,7 +110,7 @@ let DeleteDecoration (decorationToDelete: floorplan_decoration) =
let loadFloorplanView (ctx: HttpContext) =
Authenticate.Model.RequireClerkAuthentication ctx
let roomMenu = Entity.GetAllInVenue<floorplan_room> |> Array.map View.roomButton
let roomMenu = Entity.GetAllInVenue<room> |> Array.map View.roomButton
let currentClerk = Authenticate.Model.getCurrentClerk ctx
let styles = [|"dredgepos.floorplan.css"|] |> addDefaultStyles
let scripts = [|"./external/konva.min.js" ; "dredgepos.floorplan.js"|] |> addDefaultScripts

View File

@@ -39,7 +39,7 @@ let tablesInRoom (roomId: int) = //Get a list of all tables in a particular room
table "floorplan_tables"
where (eq "room_id" roomId)
}
|> db.Select<floorplan_table>
|> Database.Select<floorplan_table>
let getActiveTables (venueId: int) =
@@ -47,7 +47,7 @@ let getActiveTables (venueId: int) =
table "floorplan_tables"
where (eq "venue_id" venueId)
}
|> db.Select
|> Database.Select
|> Array.filter tableIsOpen
|> Array.map (fun table -> table.table_number)
@@ -93,7 +93,7 @@ let getTable (tableNumber : int) =
where (eq "table_number" tableNumber + eq "venue_id" (getCurrentVenue()))
}
let result = query |> db.Select<floorplan_table>
let result = query |> Database.Select<floorplan_table>
result |> first
let getTableById (id : int) =
@@ -101,14 +101,14 @@ let getTableById (id : int) =
table "floorplan_tables"
where (eq "id" id)
}
|> db.Select<floorplan_table>
|> Database.Select<floorplan_table>
|> first
let getRoom (roomId: int) =
select {
table "floorplan_rooms"
where (eq "id" roomId)
} |> db.Select<floorplan_room> |> first
} |> Database.Select<room> |> first
let updateTablePosition (floorplanTable: floorplan_table) = Entity.Update floorplanTable
@@ -117,7 +117,7 @@ let createEmptyReservation (reservation: reservation) =
table "floorplan_tables"
set {| status = 2 |}
where(eq "id" reservation.floorplan_table_id)
} |> db.Update |> ignore
} |> Database.Update |> ignore
Entity.Create reservation
@@ -154,7 +154,7 @@ let tableExists (tableNumber: int) =
select{
table "floorplan_tables"
where (eq "table_number" tableNumber + eq "venue_id" (getCurrentVenue()))
} |> db.Select<floorplan_table> |> length
} |> Database.Select<floorplan_table> |> length
match numberOfResults with
| 0 ->
@@ -169,14 +169,14 @@ let tableExists (tableNumber: int) =
| _ ->
let parentTableData = getTable allTables[0]
let parentRoom = getRoom parentTableData.room_id
let parentRoomName = parentRoom.room_name
let parentRoomName = parentRoom.name
language.getAndReplace "error_table_exists_merged" [parentRoomName; parentTableData.table_number.ToString()]
| _ ->
let tableData = getTable tableNumber
let room = getRoom tableData.room_id
language.getAndReplace "error_table_exists" [room.room_name]
language.getAndReplace "error_table_exists" [room.name]
let addNewTableWithoutOutput (newTable: floorplan_table) =
@@ -184,7 +184,7 @@ let addNewTableWithoutOutput (newTable: floorplan_table) =
table "floorplan_tables"
value newTable
}
|> db.Insert
|> Database.Insert
let addNewTable (newTable: floorplan_table) = Entity.Create newTable
@@ -238,7 +238,7 @@ let mergeTables parent child = //Merge two tables together
default_covers = parentTable.default_covers + childTable.default_covers
|}
where (eq "table_number" parent + eq "venue_id" (getCurrentVenue()))
} |> db.Update |> ignore
} |> Database.Update |> ignore
Entity.DeleteById<floorplan_table> newChildTable.id
|> ignore
@@ -251,7 +251,7 @@ let updateUnmergedTables parentTable childTable =
table "floorplan_tables"
set parentTable
where(eq "table_number" parentTable.table_number + eq "venue_id" (getCurrentVenue()))
} |> db.Update |> ignore
} |> Database.Update |> ignore
addNewTableWithoutOutput childTable |> ignore
true

View File

@@ -14,7 +14,7 @@ let ActiveInMode (value: string) = value |> (attr "data-active-in-mode")
let pageContainer (clerk: clerk) roomMenu =
let loggedInText = str (language.getAndReplace "logged_in_as" [clerk.clerk_name])
let loggedInText = str (language.getAndReplace "logged_in_as" [clerk.name])
div [_id "pageContainer"] [
div [_id "floorplanLeftColumn"] [
@@ -77,7 +77,7 @@ let pageContainer (clerk: clerk) roomMenu =
]
]
let roomButton (room: floorplan_room) = a [_class "posButton roomButton"; Value (string room.id)] [str room.room_name ]
let roomButton (room: room) = a [_class "posButton roomButton"; Value (string room.id)] [str room.name ]
let index styles scripts tags clerk decoratorRows roomMenu =
[|

32
Installer/Controller.fs Normal file
View File

@@ -0,0 +1,32 @@
module DredgePos.Installer.Controller
open System.Reflection
open DredgePos.Types
open FSharp.Reflection
let RunMigration (fsModule: System.Type) =
fsModule
.GetMethod("run")
.Invoke(null, [||])
|> ignore
Entity.Create {name=fsModule.FullName; timestamp=DredgeFramework.CurrentTime(); id=0} |> ignore
fsModule.FullName + " ran Successfully"
let RunAllMigrations () =
let completedMigrations =
try
Entity.GetAll<migration>
with
| _ -> [||]
|> Array.map (fun migration -> migration.name)
Assembly
.GetExecutingAssembly()
.GetTypes()
|> Array.filter FSharpType.IsModule
|> Array.filter (fun fsModule -> fsModule.Namespace = "DredgePos.Migrations")
|> Array.filter (fun fsModule -> not (completedMigrations |> Array.contains fsModule.FullName))
|> Array.sortBy (fun fsModule -> fsModule.Name)
|> Array.map RunMigration
|> (fun arr -> if arr.Length > 0 then arr else [|"No Migrations Were Run"|])
|> String.concat "<br/><hr/>"

2
Installer/Model.fs Normal file
View File

@@ -0,0 +1,2 @@
module DredgePos.Installer.Model

10
Installer/Router.fs Normal file
View File

@@ -0,0 +1,10 @@
module DredgePos.Installer.Router
open DredgePos
open Saturn
open Giraffe
let router = router {
pipe_through Ajax.Router.pipeline
get "/" (warbler (fun _ -> htmlString (Controller.RunAllMigrations ())))
}

View File

@@ -0,0 +1,131 @@
module DredgePos.Migrations.CreateDatabaseSchema
open DredgePos.Types
open Database
open Dapper.FSharp
open Dapper.FSharp.PostgreSQL
let CreateDatabase (db: db_config) connectionString =
let connection = connect connectionString
connection
|> NonDbSpecificQuery $"""
CREATE DATABASE {db.db_name};
"""
let addTables () =
CreateTable "sessions" [
"session_id", "varchar(200)"
"clerk_json", "text"
"clerk_id", "int"
"expires", "int"
]
CreateTable "grids" [
"name", "varchar(60)"
"rows", "int"
"cols", "int"
"data", "text"
]
CreateTable "reservations" [
"name", "varchar(100)"
"time", "int"
"covers", "int"
"floorplan_table_id", "int"
"created_at", "int"
]
CreateTable "venues" [
"name", "varchar(60)"
]
CreateTable "floorplan_tables" [
"table_number", "int"
"room_id", "int"
"venue_id", "int"
"pos_x", "int"
"pos_y", "int"
"shape", "varchar(12)"
"width", "int"
"height", "int"
"default_covers", "int"
"rotation", "int"
"merged_children", "text"
"previous_state", "text"
"status", "int"
]
CreateTable "print_groups" [
"name", "varchar(20)"
"printer_id", "int"
"venue_id", "int"
]
CreateTable "sales_categories" [
"parent", "int"
"name", "varchar(20)"
"print_group_id", "int"
"venue_id", "int"
]
CreateTable "rooms" [
"name", "varchar(20)"
"background_image", "varchar(100)"
"venue_id", "int"
]
CreateTable "floorplan_decorations" [
"room_id", "int"
"pos_x", "int"
"pos_y", "int"
"rotation", "int"
"width", "int"
"height", "int"
"image", "varchar(100)"
"venue_id", "int"
]
CreateTable "clerks" [
"name", "varchar(20)"
"login_code", "int"
"user_group_id", "int"
]
CreateTable "order_screen_page_groups" [
"order", "int"
"venue_id", "int"
"label", "varchar(40)"
"grid_id", "int"
]
CreateTable "buttons" [
"text", "varchar(60)"
"primary_action", "varchar(15)"
"primary_action_value", "varchar(20)"
"secondary_action", "varchar(15)"
"secondary_action_value", "varchar(20)"
"image", "varchar(60)"
"extra_classes", "text"
"extra_styles", "text"
]
CreateTable "items" [
"code", "varchar(40)"
"sales_category_id", "int"
"name", "varchar(60)"
"item_type", "varchar(12)"
"price1", "int"
]
CreateTable "migrations" [
"name", "varchar(100)"
"timestamp", "int"
]
let run () =
let db = getDatabaseSettings ()
$"Server={db.host};Port={db.port};User Id={db.username};Password={db.password};Include Error Detail=true"
|> CreateDatabase db
|> ignore
|> addTables

View File

@@ -0,0 +1,345 @@
module DredgePos.Migrations.PopulateTestData
open DredgeFramework
open DredgePos.Types
open System.IO
let CreatePageFromDirectory index (dir: string) =
let dirName = DirectoryInfo(dir).Name
let printGroup =
match dirName.ToLower() with
| "beer" | "wine" -> (Entity.GetFirstByColumn<print_group> "name" "Beverage").id
| _ -> (Entity.GetFirstByColumn<print_group> "name" "Food").id
let parentName =
match dirName.ToLower() with
| "beer" | "wine" -> "Beverage"
| _ -> "Food"
let parentCategory = Entity.GetFirstByColumn<sales_category> "name" parentName
if dirName.ToLower() <> "dips" && dirName.ToLower() <> "Steak Temperatures" then
let NewGrid = Entity.Create {
id=0
name=dirName
rows=8
cols=6
data=""
}
Entity.Create {
id=0
order=index
venue_id=1
label=dirName
grid_id=NewGrid.id
} |> ignore
else ()
Entity.Create {
id=0
parent=parentCategory.id
name=dirName
print_group_id=printGroup
venue_id=1
} |> ignore
dir
let CreateDefaultPrintGroups (path: string) =
Entity.Create {
id=0
name="Food"
printer_id=1
venue_id=1
} |> ignore
Entity.Create {
id=0
name="Beverage"
printer_id=1
venue_id=1
} |> ignore
path
let CreateDefaultVenue (path: string) =
let venue: venue = {
id=0
name="Megalomania"
}
Entity.Create venue
|>ignore
path
let CreateDefaultClerk (path: string) =
let venue: clerk = {
id=0
name="Josh"
login_code=1408
user_group_id=1
}
Entity.Create venue
|>ignore
path
let CreateDefaultSalesCategories (path: string) =
Entity.Create {
id=0
parent=0
name="Food"
print_group_id=(Entity.GetFirstByColumn<print_group> "name" "Food").id
venue_id=1
} |> ignore
Entity.Create {
id=0
parent=0
name="Beverage"
print_group_id=(Entity.GetFirstByColumn<print_group> "name" "Beverage").id
venue_id=1
} |> ignore
path
let CreateRooms () =
"wwwroot/images/rooms"
|> Directory.GetFiles
|> Array.filter (fun file -> Path.GetExtension file = ".png" || Path.GetExtension file = ".jpg")
|> Array.iter (fun image ->
let roomName = Path.GetFileNameWithoutExtension image
Entity.Create {
id=0
name=roomName
background_image= Path.GetFileName image
venue_id=1
} |> ignore
)
let populateEntreeGrid () =
let SalesCategory = Entity.GetFirstByColumn<sales_category> "name" "Entrees"
let DipSalesCategory = Entity.GetFirstByColumn<sales_category> "name" "Dips"
let Entrees = Entity.GetAllByColumn<item> "sales_category_id" SalesCategory.id
let Dips = Entity.GetAllByColumn<item> "sales_category_id" DipSalesCategory.id
let GridData =
[|
0; 0; 0; 0; 0; 0;
0; 0; 0; 0; 0; 0;
0; 0; 0; 0; 0; 0;
0; 0; 0; 0; 0; 0;
0; 0; 0; 0; 0; 0;
0; 0; 0; 0; 0; 0;
0; 0; 0; 0; 0; 0;
0; 0; 0; 0; 0; 0;
|]
|> Array.mapi (fun index current ->
let isFirstColumn = (index % 6) = 0
if not isFirstColumn then current else
let entree = Entrees |> Array.tryItem (index/6)
match entree with
| None -> 0
| Some x -> x.id
)
|> Array.mapi (fun index current ->
let isSecondRow = index > 6 && index < 12
if not isSecondRow then current else
let entree = Dips |> Array.tryItem (index-7)
match entree with
| None -> 0
| Some x -> x.id
)
let grid =
Entity.GetFirstByColumn<order_screen_page_group> "label" "Entrees"
|> Entity.GetRelated<grid, order_screen_page_group>
let newGrid = {grid with data=(jsonEncode {|page1=GridData|})}
Entity.Update newGrid |> ignore
()
let populateMainGrid (category: string) () =
let SalesCategory = Entity.GetFirstByColumn<sales_category> "name" category
let Mains = Entity.GetAllByColumn<item> "sales_category_id" SalesCategory.id
let getId index =
match Mains |> Array.tryItem index with
| None -> 0
| Some x -> x.id
let GridData =
[|
getId 0; 0; getId 1; 0; getId 2; 0;
0; 0; 0; 0; 0; 0;
getId 3; 0; getId 4; 0; getId 5; 0;
0; 0; 0; 0; 0; 0;
0; 0; 0; 0; 0; 0;
0; 0; 0; 0; 0; 0;
0; 0; 0; 0; 0; 0;
0; 0; 0; 0; 0; 0;
|]
let grid =
Entity.GetFirstByColumn<order_screen_page_group> "label" category
|> Entity.GetRelated<grid, order_screen_page_group>
let newGrid = {grid with data=(jsonEncode {|page1=GridData|})}
Entity.Update newGrid |> ignore
let populateDessertGrid () =
let SalesCategory = Entity.GetFirstByColumn<sales_category> "name" "Dessert"
let Desserts = Entity.GetAllByColumn<item> "sales_category_id" SalesCategory.id
let getId index =
match Desserts |> Array.tryItem index with
| None -> 0
| Some x -> x.id
let GridData =
[|
getId 0; 0; getId 1; 0; 0 ; 0;
0; 0; 0; 0; 0; 0;
0; getId 2; 0; getId 4; 0; 0;
0; 0; 0; 0; 0; 0;
0; 0; 0; 0; 0; 0;
0; 0; 0; 0; 0; 0;
0; 0; 0; 0; 0; 0;
0; 0; 0; 0; 0; 0;
|]
let grid =
Entity.GetFirstByColumn<order_screen_page_group> "label" "Dessert"
|> Entity.GetRelated<grid, order_screen_page_group>
let newGrid = {grid with data=(jsonEncode {|page1=GridData|})}
Entity.Update newGrid |> ignore
let populateBeerGrid () =
let SalesCategory = Entity.GetFirstByColumn<sales_category> "name" "Beer"
let Beers = Entity.GetAllByColumn<item> "sales_category_id" SalesCategory.id
let grid =
Entity.GetFirstByColumn<order_screen_page_group> "label" "Beer"
|> Entity.GetRelated<grid, order_screen_page_group>
let GridData =
Beers
|> Array.chunkBySize 24
|> Array.map (fun beerPage ->
let getId index =
match beerPage |> Array.tryItem index with
| None -> 0
| Some x -> x.id
[|
getId 0; getId 1; getId 2; getId 3; getId 4 ; getId 5;
0; 0; 0; 0; 0 ;0;
getId 6; getId 7; getId 8; getId 9; getId 10 ; getId 11;
0; 0; 0; 0; 0 ;0;
getId 12; getId 13; getId 14; getId 15; getId 16 ; getId 17;
0; 0; 0; 0; 0 ;0;
getId 18; getId 19; getId 20; getId 21; getId 22 ; getId 23;
0; 0; 0; 0; 0 ;0;
|]
)
|> Array.mapi (fun index beerpage -> (map [$"page{index+1}", beerpage]))
|> jsonEncode
let newGrid = {grid with data=GridData}
Entity.Update newGrid |> ignore
let populateSteakTemperaturesGrid () =
let SalesCategory = Entity.GetFirstByColumn<sales_category> "name" "Steak Temperatures"
let Temps = Entity.GetAllByColumn<item> "sales_category_id" SalesCategory.id
let grid =
Entity.GetFirstByColumn<order_screen_page_group> "label" "Steak Temperatures"
|> Entity.GetRelated<grid, order_screen_page_group>
let getId index =
match Temps |> Array.tryItem index with
| None -> 0
| Some x -> x.id
let GridData =
[|
getId 0; 0; getId 1; 0; getId 2; 0;
0; 0; 0; 0; 0; 0;
getId 3; 0; getId 4; 0; getId 5; 0;
0; 0; 0; 0; 0; 0;
0; 0; 0; 0; 0; 0;
0; 0; 0; 0; 0; 0;
0; 0; 0; 0; 0; 0;
0; 0; 0; 0; 0; 0;
|]
let newGrid = {grid with data=(jsonEncode {|page1=GridData|}); rows=4; cols=6}
Entity.Update newGrid |> ignore
let steakButtons = Entity.GetAllByColumn<button> "text" "Venison Wellington"
steakButtons |> Array.iter (fun button ->
Entity.Update {button with secondary_action="grid"; secondary_action_value=newGrid.id.ToString()} |> ignore
)
let PopulateGrids () =
populateEntreeGrid ()
|> populateMainGrid "Mains"
|> populateMainGrid "Wine"
|> populateDessertGrid
|> populateBeerGrid
|> populateSteakTemperaturesGrid
let CreateItemFromFileName (index: int) (dirName: string) (file: string) =
let extension = Path.GetExtension file
let fileName = Path.GetFileNameWithoutExtension file
let itemType =
match dirName.ToLower() with
| "dips" -> "instruction"
| "steak temperatures" -> "instruction"
| _ -> "item"
let categories = (Entity.GetAllByColumn<sales_category> "name" dirName)
let categoryID =
if categories.Length > 0 then categories[0].id
else 1
let newItem = Entity.Create {
id = 0
code = $"{dirName}0{index+1}" |> StringReplace " " ""
sales_category_id=categoryID
name=fileName
item_type=itemType
price1=10
}
let classes =
match dirName.ToLower() with
| "beer" | "dessert" -> "doubleHeight"
| "mains" | "wine" | "steak temperatures" -> "doubleHeight doubleWidth"
| "entrees" -> "doubleWidth"
| _ -> ""
Entity.Create {
id=0
text=fileName
primary_action="item"
primary_action_value=newItem.code
secondary_action="None"
secondary_action_value=""
image= $"{dirName}/{fileName}{extension}"
extra_classes=classes
extra_styles=""
} |> ignore
let CreateItemsAndButtons (dir: string) =
let dirName = DirectoryInfo(dir).Name
dir
|> Directory.GetFiles
|> Array.filter (fun file -> Path.GetExtension file = ".png" || Path.GetExtension file = ".jpg")
|> Array.iteri (fun index -> CreateItemFromFileName index dirName)
let run () =
"wwwroot/images/items"
|> CreateDefaultVenue
|> CreateDefaultClerk
|> CreateDefaultPrintGroups
|> CreateDefaultSalesCategories
|> Directory.GetDirectories
|> Array.mapi CreatePageFromDirectory
|> Array.iter CreateItemsAndButtons
|> CreateRooms
|> PopulateGrids

View File

@@ -27,7 +27,7 @@ let getImageButtonData (button: button) =
{|
extra_data = extraData
text = item.item_name
text = item.name
|}
let getGridButtonData (button: button) =
@@ -39,7 +39,7 @@ let getGridButtonData (button: button) =
let grid = Entity.GetById<grid> gridId
{|
extra_data = map ["data-grid", jsonEncode gridId] |> htmlAttributes
text = grid.grid_name
text = grid.name
|}
let getActionData (button: button) (action: string) =
@@ -93,7 +93,7 @@ let renderButton (buttonId: int) =
loadTemplateWithVars "orderScreen/grid_button" vars
let renderPage (grid: grid) (buttonHTML: string) =
let vars = map ["pageButtons", buttonHTML; "rows", string grid.grid_rows; "cols", string grid.grid_cols]
let vars = map ["pageButtons", buttonHTML; "rows", string grid.rows; "cols", string grid.cols]
loadTemplateWithVars "orderScreen/page" vars
let renderPageGroup (pageGroup: order_screen_page_group) (pageHTML: string) =
@@ -114,7 +114,7 @@ let generateSalesCategoryOverrideButtons () =
let renderGrid (grid: grid) =
let gridData = grid.grid_data |> Decode.Auto.fromString<Map<string, int[]>>
let gridData = grid.data |> Decode.Auto.fromString<Map<string, int[]>>
match gridData with
| Error _ -> "Error"

View File

@@ -14,6 +14,7 @@ module Program =
forward "/order" DredgePos.OrderScreen.Router.router
forward "/login" DredgePos.Authenticate.Router.router
forward "/reservations" DredgePos.Reservations.Router.router
forward "/install" DredgePos.Installer.Router.router
}
let app = application {

View File

@@ -10,11 +10,11 @@ let updateReservation (reservation: reservation) =
table "reservations"
set reservation
where(eq "id" reservation.id)
} |> db.Update |> ignore
} |> Database.Update |> ignore
reservation
let DeleteReservation (tableId: int) =
delete {
table "reservations"
where (eq "floorplan_table_id" tableId)
} |> db.Delete |> ignore
} |> Database.Delete |> ignore

9
config.json Normal file
View File

@@ -0,0 +1,9 @@
{
"database": {
"db_name": "dredgepos",
"username": "postgres",
"password": "root",
"host": "localhost",
"port": 5432
}
}

10
sql.log Normal file
View File

@@ -0,0 +1,10 @@
create table if not exists migrations
(
id serial
constraint migrations_pk
primary key,
"name" varchar(100) not null,
"timestamp" int not null
);

View File

@@ -11,7 +11,7 @@ interface floorplan{
tableLayer: Konva.Layer
rooms: room[]
tables: floorplan_table[]
decorations: decoration[]
decorations: floorplan_decoration[]
activeTableNumbers: number[]
selectedTableNumber: number
selectedDecorationId: number
@@ -25,7 +25,7 @@ interface floorplan{
interface floorplan_data{
tables: floorplan_table[]
decorations: decoration[]
decorations: floorplan_decoration[]
activeTableNumbers: number[]
rooms: room[]
reservations:reservation[]
@@ -122,7 +122,7 @@ const loadRoom = (roomToLoad: room) => {
button.addClass('active')
const tablesInRoom = Floorplan.tables.filter(table => table.room_id == roomToLoad.id)
const decorationsInRoom = Floorplan.decorations.filter(decoration => decoration.decoration_room == roomToLoad.id)
const decorationsInRoom = Floorplan.decorations.filter(decoration => decoration.room_id == roomToLoad.id)
decorationsInRoom.forEach(decoration => createDecorationShape(decoration, false))
tablesInRoom.forEach(createTableShape)
if(!isInMode('transfer')) {
@@ -469,21 +469,21 @@ const tableDblClicked = (event: Konva.KonvaEventObject<any>) => {
}
const createDecorationShape = (decoration:decoration, select?: boolean) => {
const createDecorationShape = (decoration:floorplan_decoration, select?: boolean) => {
const draggable = isInMode('edit')
const decorationShape = new Image()
decorationShape.onload = () => {
const decorationImage = new Konva.Image({
id: decoration.id.toString(),
x: decoration.decoration_pos_x * Floorplan.visualScale,
y: decoration.decoration_pos_y * Floorplan.visualScale,
x: decoration.pos_x * Floorplan.visualScale,
y: decoration.pos_y * Floorplan.visualScale,
image: decorationShape,
offsetX: decoration.decoration_width * 0.5 * Floorplan.visualScale,
offsetY: decoration.decoration_height * 0.5 * Floorplan.visualScale,
rotation: decoration.decoration_rotation,
width: decoration.decoration_width * Floorplan.visualScale,
height: decoration.decoration_height * Floorplan.visualScale,
offsetX: decoration.width * 0.5 * Floorplan.visualScale,
offsetY: decoration.height * 0.5 * Floorplan.visualScale,
rotation: decoration.rotation,
width: decoration.width * Floorplan.visualScale,
height: decoration.height * Floorplan.visualScale,
draggable: draggable,
});
@@ -500,7 +500,7 @@ const createDecorationShape = (decoration:decoration, select?: boolean) => {
}
}
decorationShape.src = '/images/decorations/' + decoration.decoration_image
decorationShape.src = '/images/decorations/' + decoration.image
}
const setupDecorationEvents = (decorationShape: Konva.Image) => {
@@ -541,22 +541,22 @@ const getDecorationDataById = (id: number) => {
const decorationTransformed = (event: Konva.KonvaEventObject<MouseEvent>|Konva.KonvaEventObject<TouchEvent|DragEvent|MouseEvent>) => {
let decorationShape = event.currentTarget as Konva.Image
const oldDecorationData = getDecorationDataById(Number(decorationShape.id()))
const newDecoration: decoration = {
const newDecoration: floorplan_decoration = {
id: oldDecorationData.id,
decoration_room: oldDecorationData.decoration_room,
decoration_pos_x: Math.round(decorationShape.x() / Floorplan.visualScale),
decoration_pos_y: Math.round(decorationShape.y() / Floorplan.visualScale),
decoration_rotation: Math.round(decorationShape.rotation()),
decoration_width: Math.round((decorationShape.scaleX() * decorationShape.width()) / Floorplan.visualScale),
decoration_height: Math.round((decorationShape.scaleY() * decorationShape.height()) / Floorplan.visualScale),
decoration_image: oldDecorationData.decoration_image,
room_id: oldDecorationData.room_id,
pos_x: Math.round(decorationShape.x() / Floorplan.visualScale),
pos_y: Math.round(decorationShape.y() / Floorplan.visualScale),
rotation: Math.round(decorationShape.rotation()),
width: Math.round((decorationShape.scaleX() * decorationShape.width()) / Floorplan.visualScale),
height: Math.round((decorationShape.scaleY() * decorationShape.height()) / Floorplan.visualScale),
image: oldDecorationData.image,
venue_id: oldDecorationData.venue_id,
}
saveDecoration(newDecoration)
}
const saveDecoration = (decorationToUpdate: decoration) => {
const saveDecoration = (decorationToUpdate: floorplan_decoration) => {
const decorations =
Floorplan
.decorations
@@ -576,22 +576,22 @@ const hideDecorator = () => $('#decorator').css('display', 'flex').hide()
const addDecoration = (e: Event) => {
const button = $(e.currentTarget)
const newDecoration: decoration = {
const newDecoration: floorplan_decoration = {
id: 0,
decoration_room: Floorplan.currentRoom.id,
decoration_pos_x: Floorplan.visualScaleBasis / 2,
decoration_pos_y: Floorplan.visualScaleBasis / 2,
decoration_rotation: 0,
decoration_width: 200,
decoration_height: 200,
decoration_image: button.data('image'),
room_id: Floorplan.currentRoom.id,
pos_x: Floorplan.visualScaleBasis / 2,
pos_y: Floorplan.visualScaleBasis / 2,
rotation: 0,
width: 200,
height: 200,
image: button.data('image'),
venue_id: Floorplan.currentRoom.venue_id
}
ajax('/floorplan/addDecoration', newDecoration, 'post', decorationAdded, null, null)
}
const decorationAdded = (decoration: decoration) => {
const decorationAdded = (decoration: floorplan_decoration) => {
Floorplan.decorations.push(decoration)
createDecorationShape(decoration, true)
@@ -604,7 +604,7 @@ const deleteDecoration = () => ajax(
getDecorationDataById(Floorplan.selectedDecorationId),
'post', decorationDeleted, null, null)
const decorationDeleted = (deletedDecoration:decoration) => {
const decorationDeleted = (deletedDecoration:floorplan_decoration) => {
Floorplan.decorations = Floorplan.decorations.filter(decoration => decoration.id != deletedDecoration.id)
const decorationShape = Floorplan.stage.findOne(`#${deletedDecoration.id}`)
decorationShape.destroy()
@@ -616,8 +616,10 @@ const setRoomBackground = (roomToLoad: room) => {
const height = Floorplan.floorplanDiv.height()
if(roomToLoad.background_image) {
Floorplan.floorplanDiv.css("background-image", `url(/images/rooms/${roomToLoad?.background_image})`)
Floorplan.floorplanDiv.css("background-image", `url(/images/rooms/${roomToLoad.background_image})`)
Floorplan.floorplanDiv.css("background-size", `${width}px ${height}px`)
} else {
Floorplan.floorplanDiv.css("background-image", "none")
}
}

View File

@@ -123,7 +123,7 @@ const addItemToOrderBox = (orderItem:orderItem) => {
const existingRow = orderBox
.find('tr')
.filterByData('item', orderItem.item)
.filterByData('print_group', orderItem.print_group)
.filterByData('print_group', orderItem.print_group_id)
.filterByData('cover', orderItem.cover)
.last()
@@ -186,13 +186,13 @@ const addInstructionToOrderBox = (instruction: orderItem) => {
const addNewItem = (item: item, qty = 1) => {
const salesCategory = OrderScreen.sales_categories.where('id', item.item_category)
const printGroup = OrderScreen.print_group_override ?? OrderScreen.print_groups.where('id', salesCategory.print_group)
const salesCategory = OrderScreen.sales_categories.where('id', item.category)
const printGroup = OrderScreen.print_group_override ?? OrderScreen.print_groups.where('id', salesCategory.print_group_id)
const orderItem : orderItem = {
id: OrderScreen.order_item_id_generator.next().value,
item: item,
qty: qty,
print_group: printGroup,
print_group_id: printGroup,
cover: OrderScreen.selected_cover,
}
@@ -258,17 +258,17 @@ const renderOrderBox = () => {
const createOrderRow = (orderItem: orderItem) => {
const row = $('.orderBoxTable').EmptyRow()
const price = money(orderItem.item.price1)
const itemCellText = $('<span/>').text(orderItem.item.item_name)
const itemCellText = $('<span/>').text(orderItem.item.name)
row
.addClass(`${orderItem.item.item_type}Row`)
.setColumnValue(lang('qty_header'), orderItem.qty)
.setColumnValue(lang('price_header'), price)
.setColumnValue(lang('id_header'), orderItem.item.id)
.setColumnValue(lang('total_price_header'), price.multiply(orderItem.qty))
.setColumnValue(lang('printgroup_header'), orderItem.print_group?.name)
.setColumnValue(lang('printgroup_header'), orderItem.print_group_id?.name)
.data('order-item-id', orderItem.id)
.data('order-item-id', orderItem.id)
.data('print_group', orderItem.print_group)
.data('print_group', orderItem.print_group_id)
.data('cover', orderItem.cover)
.data('item', orderItem.item)
.find('td.itemCell')
@@ -319,17 +319,17 @@ const gridHtmlGenerated = (gridData: {gridHtml:string, grid: grid}) => {
gridContainer
.show()
.width(gridCellWidth * grid.grid_cols)
.width(gridCellWidth * grid.cols)
.children('.gridContainerHeader')
.children('span')
.text(grid.grid_name)
.text(grid.name)
.parent()
.parent()
.find('.pageGroup')
.html(gridHtml)
.show()
.parent()
.height(gridCellHeight * grid.grid_rows)
.height(gridCellHeight * grid.rows)
.closest('.gridContainer')
.find('.pageNavigation')
.toggle(gridContainer.find('.gridPage').length > 1)
@@ -495,7 +495,7 @@ const freetextSubmitted = (text: string) => {
const item = Object.assign({}, OrderScreen.custom_item)
item.item_type = 'instruction'
item.item_name = text
item.name = text
addNewItem(item)
@@ -509,7 +509,7 @@ const customItemTextSubmitted = (text: string) => {
const item = Object.assign({}, OrderScreen.custom_item)
item.item_type = 'item'
item.item_name = text
item.name = text
item.price1 = price.intValue
addNewItem(item)

View File

@@ -10,7 +10,7 @@ interface order {
interface orderItem {
id: number
qty: number
print_group: print_group
print_group_id: print_group
item: item
cover: number
}
@@ -18,7 +18,7 @@ interface orderItem {
interface print_group {
id: number,
name: string,
printer: number,
printer_id: number,
venue_id: number,
}
@@ -50,21 +50,21 @@ interface floorplan_table {
id: number
}
interface decoration {
interface floorplan_decoration {
id: number
decoration_room: number
decoration_pos_x: number
decoration_pos_y: number
decoration_rotation: number
decoration_width: number
decoration_height: number
decoration_image: string
room_id: number
pos_x: number
pos_y: number
rotation: number
width: number
height: number
image: string
venue_id: number
}
interface room {
id: number
room_name: string
name: string
background_image: string
venue_id: number
}
@@ -87,26 +87,22 @@ interface keyboard {
}
interface order_screen_page{id: number; order_screen_page_group_id: number; grid_id: number}
interface grid {id: number; grid_name: string; grid_rows: number; grid_cols: number; grid_data: string}
interface grid {id: number; name: string; rows: number; cols: number; data: string}
interface item {
id: number
item_code: string
item_category: number
item_name: string
code: string
category: number
name: string
item_type: string
price1: number
price2: number
price3: number
price4: number
price5: number
}
type sales_category = {
id: number
parent: number
name: string
print_group: string
print_group_id: string
venue_id: number
}

View File

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

View File

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View File

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

View File

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

View File

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View File

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

View File

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View File

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

View File

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View File

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

View File

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

View File

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 65 KiB

View File

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 65 KiB

View File

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 63 KiB

View File

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

View File

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 87 KiB

View File

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 83 KiB

View File

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

View File

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Some files were not shown because too many files have changed in this diff Show More