Add error display to file upload
This commit is contained in:
parent
344f4bcaa5
commit
66d35428fa
7 changed files with 93 additions and 28 deletions
|
|
@ -114,6 +114,15 @@ var FileuploadFiles = Table[
|
|||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
Error: column{
|
||||
Name: "error",
|
||||
DBType: "text",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
},
|
||||
Indexes: fileuploadFileIndexes{
|
||||
FilePkey: index{
|
||||
|
|
@ -184,11 +193,12 @@ type fileuploadFileColumns struct {
|
|||
SizeBytes column
|
||||
FileUUID column
|
||||
Committer column
|
||||
Error column
|
||||
}
|
||||
|
||||
func (c fileuploadFileColumns) AsSlice() []column {
|
||||
return []column{
|
||||
c.ID, c.ContentType, c.Created, c.CreatorID, c.Deleted, c.Name, c.OrganizationID, c.Status, c.SizeBytes, c.FileUUID, c.Committer,
|
||||
c.ID, c.ContentType, c.Created, c.CreatorID, c.Deleted, c.Name, c.OrganizationID, c.Status, c.SizeBytes, c.FileUUID, c.Committer, c.Error,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
6
db/migrations/00135_fileupload_file_error.sql
Normal file
6
db/migrations/00135_fileupload_file_error.sql
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
-- +goose Up
|
||||
ALTER TABLE fileupload.file ADD COLUMN error TEXT;
|
||||
UPDATE fileupload.file SET error = '';
|
||||
ALTER TABLE fileupload.file ALTER COLUMN error SET NOT NULL;
|
||||
-- +goose Down
|
||||
ALTER TABLE fileupload.file DROP COLUMN error;
|
||||
|
|
@ -38,6 +38,7 @@ type FileuploadFile struct {
|
|||
SizeBytes int32 `db:"size_bytes" `
|
||||
FileUUID uuid.UUID `db:"file_uuid" `
|
||||
Committer null.Val[int32] `db:"committer" `
|
||||
Error string `db:"error" `
|
||||
|
||||
R fileuploadFileR `db:"-" `
|
||||
}
|
||||
|
|
@ -65,7 +66,7 @@ type fileuploadFileR struct {
|
|||
func buildFileuploadFileColumns(alias string) fileuploadFileColumns {
|
||||
return fileuploadFileColumns{
|
||||
ColumnsExpr: expr.NewColumnsExpr(
|
||||
"id", "content_type", "created", "creator_id", "deleted", "name", "organization_id", "status", "size_bytes", "file_uuid", "committer",
|
||||
"id", "content_type", "created", "creator_id", "deleted", "name", "organization_id", "status", "size_bytes", "file_uuid", "committer", "error",
|
||||
).WithParent("fileupload.file"),
|
||||
tableAlias: alias,
|
||||
ID: psql.Quote(alias, "id"),
|
||||
|
|
@ -79,6 +80,7 @@ func buildFileuploadFileColumns(alias string) fileuploadFileColumns {
|
|||
SizeBytes: psql.Quote(alias, "size_bytes"),
|
||||
FileUUID: psql.Quote(alias, "file_uuid"),
|
||||
Committer: psql.Quote(alias, "committer"),
|
||||
Error: psql.Quote(alias, "error"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -96,6 +98,7 @@ type fileuploadFileColumns struct {
|
|||
SizeBytes psql.Expression
|
||||
FileUUID psql.Expression
|
||||
Committer psql.Expression
|
||||
Error psql.Expression
|
||||
}
|
||||
|
||||
func (c fileuploadFileColumns) Alias() string {
|
||||
|
|
@ -121,10 +124,11 @@ type FileuploadFileSetter struct {
|
|||
SizeBytes omit.Val[int32] `db:"size_bytes" `
|
||||
FileUUID omit.Val[uuid.UUID] `db:"file_uuid" `
|
||||
Committer omitnull.Val[int32] `db:"committer" `
|
||||
Error omit.Val[string] `db:"error" `
|
||||
}
|
||||
|
||||
func (s FileuploadFileSetter) SetColumns() []string {
|
||||
vals := make([]string, 0, 11)
|
||||
vals := make([]string, 0, 12)
|
||||
if s.ID.IsValue() {
|
||||
vals = append(vals, "id")
|
||||
}
|
||||
|
|
@ -158,6 +162,9 @@ func (s FileuploadFileSetter) SetColumns() []string {
|
|||
if !s.Committer.IsUnset() {
|
||||
vals = append(vals, "committer")
|
||||
}
|
||||
if s.Error.IsValue() {
|
||||
vals = append(vals, "error")
|
||||
}
|
||||
return vals
|
||||
}
|
||||
|
||||
|
|
@ -195,6 +202,9 @@ func (s FileuploadFileSetter) Overwrite(t *FileuploadFile) {
|
|||
if !s.Committer.IsUnset() {
|
||||
t.Committer = s.Committer.MustGetNull()
|
||||
}
|
||||
if s.Error.IsValue() {
|
||||
t.Error = s.Error.MustGet()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *FileuploadFileSetter) Apply(q *dialect.InsertQuery) {
|
||||
|
|
@ -203,7 +213,7 @@ func (s *FileuploadFileSetter) Apply(q *dialect.InsertQuery) {
|
|||
})
|
||||
|
||||
q.AppendValues(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) {
|
||||
vals := make([]bob.Expression, 11)
|
||||
vals := make([]bob.Expression, 12)
|
||||
if s.ID.IsValue() {
|
||||
vals[0] = psql.Arg(s.ID.MustGet())
|
||||
} else {
|
||||
|
|
@ -270,6 +280,12 @@ func (s *FileuploadFileSetter) Apply(q *dialect.InsertQuery) {
|
|||
vals[10] = psql.Raw("DEFAULT")
|
||||
}
|
||||
|
||||
if s.Error.IsValue() {
|
||||
vals[11] = psql.Arg(s.Error.MustGet())
|
||||
} else {
|
||||
vals[11] = psql.Raw("DEFAULT")
|
||||
}
|
||||
|
||||
return bob.ExpressSlice(ctx, w, d, start, vals, "", ", ", "")
|
||||
}))
|
||||
}
|
||||
|
|
@ -279,7 +295,7 @@ func (s FileuploadFileSetter) UpdateMod() bob.Mod[*dialect.UpdateQuery] {
|
|||
}
|
||||
|
||||
func (s FileuploadFileSetter) Expressions(prefix ...string) []bob.Expression {
|
||||
exprs := make([]bob.Expression, 0, 11)
|
||||
exprs := make([]bob.Expression, 0, 12)
|
||||
|
||||
if s.ID.IsValue() {
|
||||
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
|
||||
|
|
@ -358,6 +374,13 @@ func (s FileuploadFileSetter) Expressions(prefix ...string) []bob.Expression {
|
|||
}})
|
||||
}
|
||||
|
||||
if s.Error.IsValue() {
|
||||
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
|
||||
psql.Quote(append(prefix, "error")...),
|
||||
psql.Arg(s.Error),
|
||||
}})
|
||||
}
|
||||
|
||||
return exprs
|
||||
}
|
||||
|
||||
|
|
@ -1074,6 +1097,7 @@ type fileuploadFileWhere[Q psql.Filterable] struct {
|
|||
SizeBytes psql.WhereMod[Q, int32]
|
||||
FileUUID psql.WhereMod[Q, uuid.UUID]
|
||||
Committer psql.WhereNullMod[Q, int32]
|
||||
Error psql.WhereMod[Q, string]
|
||||
}
|
||||
|
||||
func (fileuploadFileWhere[Q]) AliasedAs(alias string) fileuploadFileWhere[Q] {
|
||||
|
|
@ -1093,6 +1117,7 @@ func buildFileuploadFileWhere[Q psql.Filterable](cols fileuploadFileColumns) fil
|
|||
SizeBytes: psql.Where[Q, int32](cols.SizeBytes),
|
||||
FileUUID: psql.Where[Q, uuid.UUID](cols.FileUUID),
|
||||
Committer: psql.WhereNull[Q, int32](cols.Committer),
|
||||
Error: psql.Where[Q, string](cols.Error),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -192,9 +192,11 @@ func JobImport(ctx context.Context, txn bob.Executor, file_id int32) error {
|
|||
err = importCSV(ctx, file_id, parseCSVFlyover, processCSVFlyover)
|
||||
}
|
||||
if err != nil {
|
||||
log.Debug().Err(err).Msg("failed to import CSV")
|
||||
_, err := psql.Update(
|
||||
um.Table("fileupload.file"),
|
||||
um.SetCol("status").ToArg("error"),
|
||||
um.SetCol("error").ToArg(err.Error()),
|
||||
um.Where(psql.Quote("id").EQ(psql.Arg(file_id))),
|
||||
).Exec(ctx, db.PGInstance.BobDB)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ const (
|
|||
|
||||
type Upload struct {
|
||||
Created time.Time `db:"created" json:"created"`
|
||||
Error string `db:"error" json:"error"`
|
||||
Filename string `db:"filename" json:"filename"`
|
||||
ID int32 `db:"id" json:"id"`
|
||||
RecordCount int `db:"recordcount" json:"recordcount"`
|
||||
|
|
@ -92,6 +93,7 @@ func NewUpload(ctx context.Context, u User, upload file.Upload, t enums.Fileuplo
|
|||
Created: omit.From(time.Now()),
|
||||
CreatorID: omit.From(int32(u.ID)),
|
||||
Deleted: omitnull.FromPtr[time.Time](nil),
|
||||
Error: omit.From(""),
|
||||
Name: omit.From(upload.Name),
|
||||
OrganizationID: omit.From(u.Organization.ID),
|
||||
Status: omit.From(enums.FileuploadFilestatustypeUploaded),
|
||||
|
|
@ -167,6 +169,7 @@ func UploadList(ctx context.Context, org Organization) ([]Upload, error) {
|
|||
"file.created AS created",
|
||||
//"file.creator_id",
|
||||
//"file.deleted",
|
||||
"file.error AS error",
|
||||
"file.id AS id",
|
||||
"file.name AS filename",
|
||||
//"file.organization_id",
|
||||
|
|
@ -235,9 +238,9 @@ func getUploadDetailPool(ctx context.Context, file *models.FileuploadFile) (*Upl
|
|||
Tags: tags,
|
||||
})
|
||||
}
|
||||
log.Debug().Str("status", file.Status.String()).Int32("id", file.ID).Msg("returning")
|
||||
return &Upload{
|
||||
Created: file.Created,
|
||||
Error: file.Error,
|
||||
Filename: file.Name,
|
||||
ID: file.ID,
|
||||
RecordCount: len(pool_rows),
|
||||
|
|
|
|||
|
|
@ -559,6 +559,17 @@ export interface ReviewTaskListResponse {
|
|||
}
|
||||
export interface UploadDTO {
|
||||
created: string;
|
||||
error: string;
|
||||
filename: string;
|
||||
id: number;
|
||||
recordcount: number;
|
||||
status: string;
|
||||
type: string;
|
||||
csv_pool?: CSVPoolDetail;
|
||||
}
|
||||
export interface UploadOptions {
|
||||
created: Date;
|
||||
error: string;
|
||||
filename: string;
|
||||
id: number;
|
||||
recordcount: number;
|
||||
|
|
@ -567,25 +578,29 @@ export interface UploadDTO {
|
|||
csv_pool?: CSVPoolDetail;
|
||||
}
|
||||
export class Upload {
|
||||
constructor(
|
||||
public created: Date,
|
||||
public filename: string,
|
||||
public id: number,
|
||||
public recordcount: number,
|
||||
public status: string,
|
||||
public type: string,
|
||||
public csv_pool?: CSVPoolDetail,
|
||||
) {}
|
||||
created: Date;
|
||||
error: string;
|
||||
filename: string;
|
||||
id: number;
|
||||
recordcount: number;
|
||||
status: string;
|
||||
type: string;
|
||||
csv_pool?: CSVPoolDetail;
|
||||
constructor(options: UploadOptions) {
|
||||
this.created = options.created;
|
||||
this.error = options.error;
|
||||
this.filename = options.filename;
|
||||
this.id = options.id;
|
||||
this.recordcount = options.recordcount;
|
||||
this.status = options.status;
|
||||
this.type = options.type;
|
||||
this.csv_pool = options.csv_pool;
|
||||
}
|
||||
static fromJSON(json: UploadDTO): Upload {
|
||||
return new Upload(
|
||||
new Date(json.created),
|
||||
json.filename,
|
||||
json.id,
|
||||
json.recordcount,
|
||||
json.status,
|
||||
json.type,
|
||||
json.csv_pool,
|
||||
);
|
||||
return new Upload({
|
||||
...json,
|
||||
created: new Date(json.created),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -150,12 +150,11 @@ tr.has-error {
|
|||
<p>loading</p>
|
||||
</div>
|
||||
<div v-else>
|
||||
<MapMultipoint
|
||||
:bounds="session.organization!.service_area"
|
||||
<MapLocator
|
||||
:markers="[]"
|
||||
:organizationId="session.organization!.id"
|
||||
:tegola="session.urls?.tegola ?? ''"
|
||||
></MapMultipoint>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -202,8 +201,13 @@ tr.has-error {
|
|||
</div>
|
||||
|
||||
<template v-else>
|
||||
<div v-if="upload.error" class="alert alert-error" role="alert">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||
<strong>Error:</strong> Your upload failed to parse correctly. The
|
||||
specific error was: '{{ upload.error }}'
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
v-else-if="
|
||||
!upload.csv_pool?.pools || upload.csv_pool.pools.length === 0
|
||||
"
|
||||
class="alert alert-warning"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue