frontend structiure generated

This commit is contained in:
2025-04-17 17:00:15 +02:00
parent 22b6f3bd2a
commit 3ee632b683
15 changed files with 720 additions and 30 deletions

View File

@@ -30,14 +30,30 @@ services:
- DB_NAME=${DB_DATABASE} - DB_NAME=${DB_DATABASE}
- GIN_MODE=${GIN_MODE} - GIN_MODE=${GIN_MODE}
ports: ports:
- "8089:8080" - "34013:8080"
depends_on: depends_on:
db: db:
condition: service_healthy condition: service_healthy
networks: networks:
- wagfarm-net - wagfarm-net
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"] # or use the health endpoint of your API test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 5s
ui:
build: ./wagfarm-ui
container_name: wagfarm-ui
restart: always
ports:
- "34014:80"
depends_on:
api:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80"]
interval: 30s interval: 30s
timeout: 10s timeout: 10s
retries: 3 retries: 3

View File

@@ -1,5 +1,5 @@
# Stage 1: Build the Go binary # Stage 1: Build the Go binary
FROM golang:1.21-alpine AS builder FROM golang:1.24-alpine AS builder
WORKDIR /app WORKDIR /app
@@ -16,6 +16,8 @@ RUN go build -o wagfarm-api main.go
# Stage 2: Minimal runtime image # Stage 2: Minimal runtime image
FROM alpine:latest FROM alpine:latest
RUN apk add curl
WORKDIR /root/ WORKDIR /root/
# Copy the binary from the builder # Copy the binary from the builder

131
wagfarm-api/endpoints.txt Normal file
View File

@@ -0,0 +1,131 @@
GET /v1/assets/fertilizer/
GET /v1/assets/fertilizer/:id
POST /v1/assets/fertilizer/
PUT /v1/assets/fertilizer/:id
DELETE /v1/assets/fertilizer/:id
GET /v1/assets/land/
GET /v1/assets/land/:id
POST /v1/assets/land/
PUT /v1/assets/land/:id
DELETE /v1/assets/land/:id
GET /v1/assets/machine/
GET /v1/assets/machine/:id
POST /v1/assets/machine/
PUT /v1/assets/machine/:id
DELETE /v1/assets/machine/:id
GET /v1/assets/pesticide/
GET /v1/assets/pesticide/:id
POST /v1/assets/pesticide/
PUT /v1/assets/pesticide/:id
DELETE /v1/assets/pesticide/:id
GET /v1/assets/plant/
GET /v1/assets/plant/:id
POST /v1/assets/plant/
PUT /v1/assets/plant/:id
DELETE /v1/assets/plant/:id
GET /v1/assets/product/
GET /v1/assets/product/:id
POST /v1/assets/product/
PUT /v1/assets/product/:id
DELETE /v1/assets/product/:id
GET /v1/assets/seed/
GET /v1/assets/seed/:id
POST /v1/assets/seed/
PUT /v1/assets/seed/:id
DELETE /v1/assets/seed/:id
GET /v1/logs/
GET /v1/logs/:id
POST /v1/logs/
PUT /v1/logs/:id
DELETE /v1/logs/:id
GET /v1/logs/cropprotection/
GET /v1/logs/cropprotection/:id
POST /v1/logs/cropprotection/
PUT /v1/logs/cropprotection/:id
DELETE /v1/logs/cropprotection/:id
GET /v1/logs/fertilizer/
GET /v1/logs/fertilizer/:id
POST /v1/logs/fertilizer/
PUT /v1/logs/fertilizer/:id
DELETE /v1/logs/fertilizer/:id
GET /v1/logs/harvest/
GET /v1/logs/harvest/:id
POST /v1/logs/harvest/
PUT /v1/logs/harvest/:id
DELETE /v1/logs/harvest/:id
GET /v1/logs/seeding/
GET /v1/logs/seeding/:id
POST /v1/logs/seeding/
PUT /v1/logs/seeding/:id
DELETE /v1/logs/seeding/:id
GET /v1/taxonomy/crop/
GET /v1/taxonomy/crop/:id
POST /v1/taxonomy/crop/
PUT /v1/taxonomy/crop/:id
DELETE /v1/taxonomy/crop/:id
GET /v1/taxonomy/customer/
GET /v1/taxonomy/customer/:id
POST /v1/taxonomy/customer/
PUT /v1/taxonomy/customer/:id
DELETE /v1/taxonomy/customer/:id
GET /v1/taxonomy/fertilizertype/
GET /v1/taxonomy/fertilizertype/:id
POST /v1/taxonomy/fertilizertype/
PUT /v1/taxonomy/fertilizertype/:id
DELETE /v1/taxonomy/fertilizertype/:id
GET /v1/taxonomy/ingredient/
GET /v1/taxonomy/ingredient/:id
POST /v1/taxonomy/ingredient/
PUT /v1/taxonomy/ingredient/:id
DELETE /v1/taxonomy/ingredient/:id
GET /v1/taxonomy/pesticidetype/
GET /v1/taxonomy/pesticidetype/:id
POST /v1/taxonomy/pesticidetype/
PUT /v1/taxonomy/pesticidetype/:id
DELETE /v1/taxonomy/pesticidetype/:id
GET /v1/taxonomy/producttype/
GET /v1/taxonomy/producttype/:id
POST /v1/taxonomy/producttype/
PUT /v1/taxonomy/producttype/:id
DELETE /v1/taxonomy/producttype/:id
GET /v1/taxonomy/seedingcondition/
GET /v1/taxonomy/seedingcondition/:id
POST /v1/taxonomy/seedingcondition/
PUT /v1/taxonomy/seedingcondition/:id
DELETE /v1/taxonomy/seedingcondition/:id
GET /v1/taxonomy/seedingtechnique/
GET /v1/taxonomy/seedingtechnique/:id
POST /v1/taxonomy/seedingtechnique/
PUT /v1/taxonomy/seedingtechnique/:id
DELETE /v1/taxonomy/seedingtechnique/:id
GET /v1/taxonomy/seedtype/
GET /v1/taxonomy/seedtype/:id
POST /v1/taxonomy/seedtype/
PUT /v1/taxonomy/seedtype/:id
DELETE /v1/taxonomy/seedtype/:id
GET /v1/taxonomy/seller/
GET /v1/taxonomy/seller/:id
POST /v1/taxonomy/seller/
PUT /v1/taxonomy/seller/:id
DELETE /v1/taxonomy/seller/:id

View File

@@ -1,6 +1,6 @@
module wagfarm-api module wagfarm-api
go 1.20 go 1.24.2
require ( require (
github.com/gin-gonic/gin v1.10.0 github.com/gin-gonic/gin v1.10.0
@@ -19,8 +19,8 @@ require (
github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/go-sql-driver/mysql v1.7.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect github.com/goccy/go-json v0.10.2 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.5.5 // indirect github.com/jackc/pgx/v5 v5.5.5 // indirect
@@ -29,19 +29,22 @@ require (
github.com/jinzhu/now v1.1.5 // indirect github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/leodido/go-urn v1.4.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/stretchr/testify v1.10.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect github.com/ugorji/go/codec v1.2.12 // indirect
golang.org/x/arch v0.8.0 // indirect golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.23.0 // indirect golang.org/x/crypto v0.37.0 // indirect
golang.org/x/net v0.25.0 // indirect golang.org/x/net v0.39.0 // indirect
golang.org/x/sync v0.1.0 // indirect golang.org/x/sync v0.13.0 // indirect
golang.org/x/sys v0.20.0 // indirect golang.org/x/sys v0.32.0 // indirect
golang.org/x/text v0.15.0 // indirect golang.org/x/text v0.24.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

View File

@@ -6,7 +6,9 @@ github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
@@ -14,16 +16,18 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8= github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
@@ -43,6 +47,10 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
@@ -54,7 +62,12 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -68,6 +81,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
@@ -75,33 +90,28 @@ github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZ
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.5.0/go.mod h1:FFla/fJuCvyTi7rJQd27qlNX2v3L6deTR1GgTjSOLPo=
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
gorm.io/driver/postgres v1.5.11 h1:ubBVAfbKEUld/twyKZ0IYn9rSQh448EdelLYk9Mv314= gorm.io/driver/postgres v1.5.11 h1:ubBVAfbKEUld/twyKZ0IYn9rSQh448EdelLYk9Mv314=
gorm.io/driver/postgres v1.5.11/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI= gorm.io/driver/postgres v1.5.11/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A=
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=

8
wagfarm-ui/Dockerfile Normal file
View File

@@ -0,0 +1,8 @@
# Use Nginx as the base image
FROM nginx:alpine
# Copy the frontend files into the Nginx default directory
COPY ./ /usr/share/nginx/html
# Expose the default Nginx port (80)
EXPOSE 80

39
wagfarm-ui/css/forms.css Normal file
View File

@@ -0,0 +1,39 @@
/* forms.css */
.form-group {
margin-bottom: 1rem;
}
label {
display: block;
margin-bottom: 0.5rem;
font-weight: bold;
}
input[type="text"],
input[type="date"],
textarea,
select {
width: 100%;
padding: 0.5rem;
border: 1px solid #ddd;
border-radius: 3px;
font-size: 1rem;
}
textarea {
height: 100px;
}
button[type="submit"] {
background: #4a7c59;
color: white;
border: none;
padding: 0.7rem 1rem;
cursor: pointer;
font-size: 1rem;
border-radius: 3px;
}
button[type="submit"]:hover {
background: #3d6549;
}

120
wagfarm-ui/css/style.css Normal file
View File

@@ -0,0 +1,120 @@
/* styles.css */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: Arial, sans-serif;
line-height: 1.6;
color: #333;
}
header {
background: #4a7c59;
color: #fff;
padding: 1rem;
}
header h1 {
margin-bottom: 1rem;
}
nav ul {
display: flex;
list-style: none;
}
nav ul li {
margin-right: 1rem;
}
nav ul li a {
color: #fff;
text-decoration: none;
padding: 0.5rem;
}
nav ul li a.active {
background: #fff;
color: #4a7c59;
border-radius: 3px;
}
.container {
display: flex;
max-width: 1200px;
margin: 0 auto;
padding: 1rem;
}
.sidebar {
flex: 1;
margin-right: 2rem;
}
.content {
flex: 3;
}
.log-item, .asset-item, .taxonomy-item {
border: 1px solid #ddd;
padding: 1rem;
margin-bottom: 1rem;
border-radius: 3px;
}
.actions {
margin-top: 0.5rem;
}
.actions button {
padding: 0.3rem 0.5rem;
margin-right: 0.5rem;
cursor: pointer;
}
.view-btn {
background: #4a7c59;
color: white;
border: none;
}
.edit-btn {
background: #f9a826;
color: white;
border: none;
}
.delete-btn {
background: #e74c3c;
color: white;
border: none;
}
.notification {
position: fixed;
top: 20px;
right: 20px;
padding: 10px 20px;
border-radius: 5px;
color: white;
z-index: 1000;
}
.notification.success {
background-color: #2ecc71;
}
.notification.error {
background-color: #e74c3c;
}
footer {
background: #333;
color: #fff;
text-align: center;
padding: 1rem;
margin-top: 2rem;
}

86
wagfarm-ui/index.html Normal file
View File

@@ -0,0 +1,86 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Farm Work Tracker</title>
<link rel="stylesheet" href="css/styles.css">
<link rel="stylesheet" href="css/forms.css">
</head>
<body>
<header>
<h1>Farm Work Tracker</h1>
<nav>
<ul>
<li><a href="#" class="nav-link active" data-entity="logs">Logs</a></li>
<li><a href="#" class="nav-link" data-entity="assets">Assets</a></li>
<li><a href="#" class="nav-link" data-entity="taxonomies">Taxonomies</a></li>
</ul>
</nav>
</header>
<main>
<div class="container">
<div class="sidebar">
<div id="logs-form-container" class="entity-form">
<h2>Create New Log</h2>
<form id="log-create-form">
<div class="form-group">
<label for="title">Title</label>
<input type="text" id="title" name="title" required>
</div>
<div class="form-group">
<label for="date">Date</label>
<input type="date" id="date" name="date" required>
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea id="description" name="description"></textarea>
</div>
<button type="submit">Create Log</button>
</form>
</div>
<div id="assets-form-container" class="entity-form" style="display: none;">
<h2>Create New Asset</h2>
<form id="asset-create-form">
<!-- Asset form fields -->
<button type="submit">Create Asset</button>
</form>
</div>
<div id="taxonomies-form-container" class="entity-form" style="display: none;">
<h2>Create New Taxonomy</h2>
<form id="taxonomy-create-form">
<!-- Taxonomy form fields -->
<button type="submit">Create Taxonomy</button>
</form>
</div>
</div>
<div class="content">
<div class="list-container">
<h2>Entity List</h2>
<div id="entity-list"></div>
</div>
<div class="detail-container">
<h2>Details</h2>
<div id="detail-view"></div>
</div>
<div class="edit-container" style="display: none;">
<h2>Edit</h2>
<div id="edit-form"></div>
</div>
</div>
</div>
</main>
<footer>
<p>Farm Work Tracker &copy; 2025</p>
</footer>
<script type="module" src="js/app.js"></script>
</body>
</html>

64
wagfarm-ui/js/api.js Normal file
View File

@@ -0,0 +1,64 @@
// api.js
const API = {
baseUrl: 'https://your-api-url.com/api',
async get(endpoint) {
try {
const response = await fetch(`${this.baseUrl}/${endpoint}`);
if (!response.ok) throw new Error(`API Error: ${response.status}`);
return await response.json();
} catch (error) {
console.error('GET request failed:', error);
throw error;
}
},
async post(endpoint, data) {
try {
const response = await fetch(`${this.baseUrl}/${endpoint}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
if (!response.ok) throw new Error(`API Error: ${response.status}`);
return await response.json();
} catch (error) {
console.error('POST request failed:', error);
throw error;
}
},
async put(endpoint, data) {
try {
const response = await fetch(`${this.baseUrl}/${endpoint}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
if (!response.ok) throw new Error(`API Error: ${response.status}`);
return await response.json();
} catch (error) {
console.error('PUT request failed:', error);
throw error;
}
},
async delete(endpoint) {
try {
const response = await fetch(`${this.baseUrl}/${endpoint}`, {
method: 'DELETE'
});
if (!response.ok) throw new Error(`API Error: ${response.status}`);
return await response.json();
} catch (error) {
console.error('DELETE request failed:', error);
throw error;
}
}
};
export default API;

109
wagfarm-ui/js/app.js Normal file
View File

@@ -0,0 +1,109 @@
import LogsModule from './entities/logs.js';
import AssetsModule from './entities/assets.js';
import TaxonomiesModule from './entities/taxonomies.js';
// State to track which entity type is active
let activeEntityType = 'logs';
document.addEventListener('DOMContentLoaded', () => {
// Initialize navigation
setupNavigation();
// Load the default entity type
loadEntityList(activeEntityType);
// Setup form handlers
setupFormHandlers();
});
function setupNavigation() {
const navLinks = document.querySelectorAll('.nav-link');
navLinks.forEach(link => {
link.addEventListener('click', (e) => {
e.preventDefault();
const entityType = e.target.dataset.entity;
// Update active link
navLinks.forEach(l => l.classList.remove('active'));
e.target.classList.add('active');
// Update active entity and load data
activeEntityType = entityType;
loadEntityList(entityType);
// Show the appropriate form
document.querySelectorAll('.entity-form').forEach(form => {
form.style.display = 'none';
});
document.getElementById(`${entityType}-form-container`).style.display = 'block';
});
});
}
async function loadEntityList(entityType) {
// Clear previous content
document.getElementById('entity-list').innerHTML = '<p>Loading...</p>';
try {
let entities;
// Get data based on entity type
switch(entityType) {
case 'logs':
entities = await LogsModule.getAllLogs();
LogsModule.renderLogsList(entities, 'entity-list');
break;
case 'assets':
entities = await AssetsModule.getAllAssets();
AssetsModule.renderAssetsList(entities, 'entity-list');
break;
case 'taxonomies':
entities = await TaxonomiesModule.getAllTaxonomies();
TaxonomiesModule.renderTaxonomiesList(entities, 'entity-list');
break;
}
} catch (error) {
document.getElementById('entity-list').innerHTML = `<p>Error loading data: ${error.message}</p>`;
}
}
function setupFormHandlers() {
// Log creation form
document.getElementById('log-create-form').addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const logData = {
title: formData.get('title'),
date: formData.get('date'),
description: formData.get('description')
// Add more fields as needed
};
try {
await LogsModule.createLog(logData);
e.target.reset();
if (activeEntityType === 'logs') {
loadEntityList('logs');
}
showNotification('Log created successfully');
} catch (error) {
showNotification(`Error: ${error.message}`, 'error');
}
});
// Add similar handlers for assets and taxonomies
}
function showNotification(message, type = 'success') {
const notification = document.createElement('div');
notification.className = `notification ${type}`;
notification.textContent = message;
document.body.appendChild(notification);
// Remove after 3 seconds
setTimeout(() => {
notification.remove();
}, 3000);
}

View File

View File

@@ -0,0 +1,102 @@
// logs.js
import API from '../api.js';
const LogsModule = {
async getAllLogs() {
return await API.get('logs');
},
async getLog(id) {
return await API.get(`logs/${id}`);
},
async createLog(logData) {
return await API.post('logs', logData);
},
async updateLog(id, logData) {
return await API.put(`logs/${id}`, logData);
},
async deleteLog(id) {
return await API.delete(`logs/${id}`);
},
renderLogsList(logs, containerId) {
const container = document.getElementById(containerId);
container.innerHTML = '';
logs.forEach(log => {
const logElement = document.createElement('div');
logElement.className = 'log-item';
logElement.innerHTML = `
<h3>${log.title || 'Untitled Log'}</h3>
<p>${log.date || 'No date'}</p>
<div class="actions">
<button class="view-btn" data-id="${log.id}">View</button>
<button class="edit-btn" data-id="${log.id}">Edit</button>
<button class="delete-btn" data-id="${log.id}">Delete</button>
</div>
`;
container.appendChild(logElement);
});
// Add event listeners
this.addEventListeners(containerId);
},
addEventListeners(containerId) {
const container = document.getElementById(containerId);
container.addEventListener('click', async (e) => {
const id = e.target.dataset.id;
if (!id) return;
if (e.target.classList.contains('view-btn')) {
const log = await this.getLog(id);
// Display log details
document.getElementById('detail-view').innerHTML = `
<h2>${log.title || 'Untitled Log'}</h2>
<p>Date: ${log.date || 'No date'}</p>
<p>Description: ${log.description || 'No description'}</p>
<!-- Add more fields as needed -->
`;
} else if (e.target.classList.contains('edit-btn')) {
const log = await this.getLog(id);
// Populate edit form
document.getElementById('edit-form').innerHTML = `
<form id="log-edit-form" data-id="${log.id}">
<input type="text" name="title" value="${log.title || ''}">
<input type="date" name="date" value="${log.date || ''}">
<textarea name="description">${log.description || ''}</textarea>
<button type="submit">Save Changes</button>
</form>
`;
document.getElementById('log-edit-form').addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const logData = {
title: formData.get('title'),
date: formData.get('date'),
description: formData.get('description')
};
await this.updateLog(id, logData);
// Refresh the list
const logs = await this.getAllLogs();
this.renderLogsList(logs, containerId);
});
} else if (e.target.classList.contains('delete-btn')) {
if (confirm('Are you sure you want to delete this log?')) {
await this.deleteLog(id);
// Refresh the list
const logs = await this.getAllLogs();
this.renderLogsList(logs, containerId);
}
}
});
}
};
export default LogsModule;

View File

0
wagfarm-ui/js/util.js Normal file
View File