Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an option to remove page icon #1473

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 31 additions & 8 deletions client/web/compose/src/views/Admin/Pages/Edit.vue
Original file line number Diff line number Diff line change
Expand Up @@ -785,17 +785,28 @@
v-else
class="d-flex flex-wrap"
>
<img
<div
v-for="a in attachments"
:key="a.attachmentID"
:src="a.src"
:alt="a.name"
width="auto"
height="50"
:class="{ 'selected-icon': selectedAttachmentID === a.attachmentID }"
class="rounded pointer m-2"
@click="toggleSelectedIcon(a.attachmentID)"
class="d-flex flex-column align-items-center"
>
<img
:src="a.src"
:alt="a.name"
width="auto"
height="50"
:class="{ 'selected-icon': selectedAttachmentID === a.attachmentID }"
class="rounded pointer m-2"
@click="toggleSelectedIcon(a.attachmentID)"
>
<b-button
variant="outline-danger"
size="sm"
@click="deleteAttachment(a.attachmentID)"
>
X
</b-button>
</div>
</div>
</b-form-group>
</template>
Expand Down Expand Up @@ -1236,6 +1247,11 @@ export default {
const baseURL = this.$ComposeAPI.baseURL
this.attachments = []

// If there are no attachments, clear the icon from page config
if (attachments.length === 0) {
this.page.config.navItem.icon = {}
}

if (attachments) {
attachments.forEach(a => {
const src = !a.url.includes(baseURL) ? this.makeAttachmentUrl(a.url) : a.url
Expand All @@ -1246,6 +1262,13 @@ export default {
.catch(this.toastErrorHandler(this.$t('notification:page.iconFetchFailed')))
},

async deleteAttachment (attachmentID) {
return this.$ComposeAPI.iconDelete({ iconID: attachmentID })
.then(() => {
this.fetchAttachments()
})
},

addLayoutAction () {
this.layoutEditor.layout.addAction()
},
Expand Down
38 changes: 38 additions & 0 deletions lib/js/src/api-clients/compose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1337,6 +1337,44 @@ export default class Compose {
return '/icon/'
}

// Delete icon
async iconDelete (a: KV, extra: AxiosRequestConfig = {}): Promise<KV> {
const {
iconID,
} = (a as KV) || {}
if (!iconID) {
throw Error('field iconID is empty')
}
const cfg: AxiosRequestConfig = {
...extra,
method: 'delete',
url: this.iconDeleteEndpoint({
iconID,
}),
}

return this.api().request(cfg).then(result => stdResolve(result))
}

iconDeleteCancellable (a: KV, extra: AxiosRequestConfig = {}): { response: (a: KV, extra?: AxiosRequestConfig) => Promise<KV>; cancel: () => void; } {
const cancelTokenSource = axios.CancelToken.source();
let options = {...extra, cancelToken: cancelTokenSource.token }

return {
response: () => this.iconDelete(a, options),
cancel: () => {
cancelTokenSource.cancel();
}
}
}

iconDeleteEndpoint (a: KV): string {
const {
iconID,
} = a || {}
return `/icon/${iconID}`
}

// List available page layouts
async pageLayoutListNamespace (a: KV, extra: AxiosRequestConfig = {}): Promise<KV> {
const {
Expand Down
10 changes: 10 additions & 0 deletions server/compose/rest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,16 @@ endpoints:
- name: icon
type: "*multipart.FileHeader"
title: Icon to upload
- name: delete
path: "/{iconID}"
method: DELETE
title: Delete icon
parameters:
path:
- type: uint64
name: iconID
required: true
title: Icon ID

- title: Page Layouts
description: Compose page layouts
Expand Down
19 changes: 19 additions & 0 deletions server/compose/rest/handlers/icon.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ type (
IconAPI interface {
List(context.Context, *request.IconList) (interface{}, error)
Upload(context.Context, *request.IconUpload) (interface{}, error)
Delete(context.Context, *request.IconDelete) (interface{}, error)
}

// HTTP API interface
Icon struct {
List func(http.ResponseWriter, *http.Request)
Upload func(http.ResponseWriter, *http.Request)
Delete func(http.ResponseWriter, *http.Request)
}
)

Expand Down Expand Up @@ -62,6 +64,22 @@ func NewIcon(h IconAPI) *Icon {
return
}

api.Send(w, r, value)
},
Delete: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewIconDelete()
if err := params.Fill(r); err != nil {
api.Send(w, r, err)
return
}

value, err := h.Delete(r.Context(), params)
if err != nil {
api.Send(w, r, err)
return
}

api.Send(w, r, value)
},
}
Expand All @@ -72,5 +90,6 @@ func (h Icon) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.H
r.Use(middlewares...)
r.Get("/icon/", h.List)
r.Post("/icon/", h.Upload)
r.Delete("/icon/{iconID}", h.Delete)
})
}
19 changes: 19 additions & 0 deletions server/compose/rest/icon.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package rest

import (
"context"
"github.com/cortezaproject/corteza/server/pkg/api"
"github.com/cortezaproject/corteza/server/pkg/auth"
"github.com/cortezaproject/corteza/server/pkg/errors"
"mime/multipart"

"github.com/cortezaproject/corteza/server/compose/rest/request"
Expand Down Expand Up @@ -56,6 +59,9 @@ func (ctrl *Icon) List(ctx context.Context, r *request.IconList) (interface{}, e
return nil, err
}

//Get only the undeleted icons
f.Deleted = filter.StateExcluded

set, f, err = ctrl.attachment.Find(ctx, f)
return ctrl.makeIconFilterPayload(ctx, set, f, err)
}
Expand Down Expand Up @@ -105,3 +111,16 @@ func (ctrl *Icon) makeIconFilterPayload(ctx context.Context, nn types.Attachment

return res, nil
}

func (ctrl *Icon) Delete(ctx context.Context, r *request.IconDelete) (interface{}, error) {
if !auth.GetIdentityFromContext(ctx).Valid() {
return nil, errors.Unauthorized("cannot delete icon")
}

_, err := ctrl.attachment.FindByID(ctx, 0, r.IconID)
if err != nil {
return nil, err
}

return api.OK(), ctrl.attachment.DeleteByID(ctx, 0, r.IconID)
}
42 changes: 42 additions & 0 deletions server/compose/rest/request/icon.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ type (
// Icon to upload
Icon *multipart.FileHeader
}

IconDelete struct {
// IconID PATH parameter
//
// Icon ID
IconID uint64 `json:",string"`
}
)

// NewIconList request
Expand Down Expand Up @@ -191,3 +198,38 @@ func (r *IconUpload) Fill(req *http.Request) (err error) {

return err
}

// NewIconDelete request
func NewIconDelete() *IconDelete {
return &IconDelete{}
}

// Auditable returns all auditable/loggable parameters
func (r IconDelete) Auditable() map[string]interface{} {
return map[string]interface{}{
"iconID": r.IconID,
}
}

// Auditable returns all auditable/loggable parameters
func (r IconDelete) GetIconID() uint64 {
return r.IconID
}

// Fill processes request and fills internal variables
func (r *IconDelete) Fill(req *http.Request) (err error) {

{
var val string
// path params

val = chi.URLParam(req, "iconID")
r.IconID, err = payload.ParseUint64(val), nil
if err != nil {
return err
}

}

return err
}
2 changes: 2 additions & 0 deletions server/compose/types/attachment.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ type (
FieldName string `json:"fieldName,omitempty"`
Filter string `json:"filter"`

Deleted filter.State `json:"deleted"`

// Check fn is called by store backend for each resource found function can
// modify the resource and return false if store should not return it
//
Expand Down
7 changes: 7 additions & 0 deletions server/store/adapters/rdbms/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,13 @@ func DefaultFilters() (f *extendedFilters) {
return
}

// Add a filter expression for deleted attachments
if f.Deleted == filter.StateExcluded {
ee = append(ee, goqu.C("deleted_at").IsNull())
} else if f.Deleted == filter.StateExclusive {
ee = append(ee, goqu.C("deleted_at").IsNotNull())
}

return ee, f, nil
}

Expand Down