Add saved filters backend [SCI-5977] (#3509)

* Add saved filters backend [SCI-5977]

* Rework filter saving [SCI-5977]

Co-authored-by: Martin Artnik <martin@scinote.net>
This commit is contained in:
aignatov-bio 2021-08-26 14:50:54 +02:00 committed by Martin Artnik
parent ef0e45be04
commit b269f3f612
12 changed files with 197 additions and 27 deletions

View file

@ -0,0 +1,34 @@
# frozen_string_literal: true
class BmtFiltersController < ApplicationController
before_action :check_manage_permission, except: :index
def index
render json: BmtFilter.all, each_serializer: BmtFilterSerializer
end
def create
filter = BmtFilter.new(filters_params)
filter.created_by = current_user
if filter.save
render json: filter, serializer: BmtFilterSerializer
else
render json: filter.errors.full_messages, status: :unprocessable_entity
end
end
def destroy
filter = BmtFilter.find(params[:id])
render json: { status: filter.destroy }
end
private
def filters_params
params.require(:bmt_filter).permit(:name, :filters)
end
def check_manage_permission
render_403 && return unless can_manage_bmt_filters?(@current_team)
end
end

View file

@ -10,27 +10,39 @@ window.initBMTFilter = () => {
el: '#bmtFilterContainer', el: '#bmtFilterContainer',
data: () => { data: () => {
return { return {
saved_filters: [] savedFilters: [],
filters: []
}; };
}, },
components: { components: {
'filter-container': FilterContainer 'filter-container': FilterContainer
},
methods: {
updateFilters(filters) {
this.filters = filters;
},
getFilters() {
return this.filters;
}
} }
}); });
$('#bmtFilterContainer').on('click', (e) => e.stopPropagation()); $('#bmtFilterContainer').on('click', (e) => e.stopPropagation());
$( "#saveBmtFilterForm" ).off().submit(function(e) { $("#saveBmtFilterForm" )
let filterName = $(this).find('input#filter_name').val(); .off()
bmtFilterContainer.saved_filters.push({ .on('ajax:before', function() {
id: bmtFilterContainer.saved_filters.length, $('#bmt_filter_filters').val(JSON.stringify(bmtFilterContainer.getFilters()));
filter_name: filterName, })
filters: [] .on('ajax:success', function(e, result) {
bmtFilterContainer.savedFilters.push(result.data);
$('#modalSaveBmtFilter').modal('hide');
}); });
});
$.get($('#bmtFilterContainer').data('url-saved-filters'), function(result) {
bmtFilterContainer.savedFilters = result.data;
})
}; };
$('.repository-show').on('click', '.open-save-bmt-modal', () => { $('.repository-show').on('click', '.open-save-bmt-modal', () => {
$('#modalSaveBmtFilter').modal('show') $('#modalSaveBmtFilter').modal('show');
}) })

View file

@ -8,10 +8,10 @@
</div> </div>
<div class="dropdown-menu saved-filters-container"> <div class="dropdown-menu saved-filters-container">
<SavedFilterElement <SavedFilterElement
v-for="(saved_filter, index) in saved_filters" v-for="(savedFilter, index) in savedFilters"
:key="saved_filter.id" :key="savedFilter.id"
:saved_filter.sync="saved_filters[index]" :savedFilter.sync="savedFilters[index]"
@saved_filter:delete="saved_filters.splice(index, 1)" @savedFilter:delete="savedFilters.splice(index, 1)"
/> />
</div> </div>
</div> </div>
@ -50,15 +50,15 @@
export default { export default {
name: 'FilterContainer', name: 'FilterContainer',
props: {
container: Object,
savedFilters: Array
},
data() { data() {
return { return {
filters: [] filters: []
} }
}, },
props: {
container: Object,
saved_filters: Array
},
components: { FilterElement, SavedFilterElement }, components: { FilterElement, SavedFilterElement },
computed: { computed: {
searchJSON() { searchJSON() {
@ -77,6 +77,7 @@
}, },
updateFilter(filter) { updateFilter(filter) {
this.filters.find((f) => f.id === filter.id).data = filter.data; this.filters.find((f) => f.id === filter.id).data = filter.data;
this.$emit('filters:update', this.searchJSON);
}, },
clearAllFilters() { clearAllFilters() {
this.filters = []; this.filters = [];

View file

@ -1,7 +1,7 @@
<template> <template>
<div class="saved-filter-element"> <div class="saved-filter-element">
{{ saved_filter.filter_name }} {{ savedFilter.attributes.name }}
<button class="btn btn-light icon-btn" @click="$emit('saved_filter:delete')"> <button class="btn btn-light icon-btn" @click="deleteFilter">
<i class="fas fa-trash"></i> <i class="fas fa-trash"></i>
</button> </button>
</div> </div>
@ -11,7 +11,20 @@
export default { export default {
name: 'SavedFilterElement', name: 'SavedFilterElement',
props: { props: {
saved_filter: Object savedFilter: Object
},
methods: {
deleteFilter() {
let filter = this
$.ajax({
url: this.savedFilter.attributes.delete_url,
type: 'DELETE',
dataType: 'json',
success: function() {
filter.$emit('savedFilter:delete')
}
});
}
} }
} }
</script> </script>

13
app/models/bmt_filter.rb Normal file
View file

@ -0,0 +1,13 @@
# frozen_string_literal: true
class BmtFilter < ApplicationRecord
attr_accessor :delete_url
belongs_to :created_by,
foreign_key: :created_by_id,
class_name: 'User',
optional: true
validates :name, :filters, presence: true
end

View file

@ -36,6 +36,10 @@ Canaid::Permissions.register_for(Team) do
user.is_normal_user_or_admin_of_team?(team) user.is_normal_user_or_admin_of_team?(team)
end end
can :manage_bmt_filters do |user, team|
user.is_normal_user_or_admin_of_team?(team)
end
# repository: create, copy # repository: create, copy
can :create_repositories do |user, team| can :create_repositories do |user, team|
within_limits = Repository.within_global_limits? within_limits = Repository.within_global_limits?

View file

@ -0,0 +1,11 @@
# frozen_string_literal: true
class BmtFilterSerializer < ActiveModel::Serializer
include Rails.application.routes.url_helpers
attributes :name, :filters, :delete_url
def delete_url
bmt_filter_path(object.id)
end
end

View file

@ -7,11 +7,12 @@
<%= t('repositories.show.bmt_search.save_filters') %> <%= t('repositories.show.bmt_search.save_filters') %>
</h4> </h4>
</div> </div>
<%= form_with url: '', method: :post, :html => { :id => "saveBmtFilterForm" } do |f| %> <%= form_with model: BmtFilter.new, method: :post, :html => { :id => "saveBmtFilterForm" } do |f| %>
<div class="modal-body"> <div class="modal-body">
<%= f.hidden_field :filters, class: "sci-input-field" %>
<div class="sci-input-container"> <div class="sci-input-container">
<%= f.label :filter_name %> <%= f.label :name %>
<%= f.text_field :filter_name, class: "sci-input-field" %> <%= f.text_field :name, class: "sci-input-field" %>
</div> </div>
</div> </div>

View file

@ -96,8 +96,11 @@
<span class="fas fa-microscope"></span> <span class="fas fa-microscope"></span>
<%= t('repositories.show.bmt_search.bmt_filter') %> <%= t('repositories.show.bmt_search.bmt_filter') %>
</button> </button>
<div class="dropdown-menu bmt-filters-container" id="bmtFilterContainer"> <div class="dropdown-menu bmt-filters-container" id="bmtFilterContainer" data-url-saved-filters="<%= bmt_filters_path %>">
<filter-container :saved_filters="saved_filters"></filter-container> <filter-container
@filters:update="updateFilters"
:saved-filters.sync="savedFilters"
:filters.sync="filters" />
</div> </div>
</div> </div>
<button <button

View file

@ -779,6 +779,8 @@ Rails.application.routes.draw do
end end
end end
resources :bmt_filters, only: %i(index create destroy)
match '/marvin4js-license.cxl', to: 'bio_eddie_assets#license', via: :get match '/marvin4js-license.cxl', to: 'bio_eddie_assets#license', via: :get
match 'biomolecule_toolkit/*path', to: 'bio_eddie_assets#bmt_request', match 'biomolecule_toolkit/*path', to: 'bio_eddie_assets#bmt_request',

View file

@ -0,0 +1,12 @@
# frozen_string_literal: true
class CreateBmtFilters < ActiveRecord::Migration[6.1]
def change
create_table :bmt_filters do |t|
t.string :name, null: false
t.string :filters, null: false
t.references :created_by, index: true, foreign_key: { to_table: :users }
t.timestamps
end
end
end

View file

@ -313,6 +313,39 @@ CREATE SEQUENCE public.assets_id_seq
ALTER SEQUENCE public.assets_id_seq OWNED BY public.assets.id; ALTER SEQUENCE public.assets_id_seq OWNED BY public.assets.id;
--
-- Name: bmt_filters; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.bmt_filters (
id bigint NOT NULL,
name character varying NOT NULL,
filters character varying NOT NULL,
created_by_id bigint,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL
);
--
-- Name: bmt_filters_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.bmt_filters_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: bmt_filters_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.bmt_filters_id_seq OWNED BY public.bmt_filters.id;
-- --
-- Name: checklist_items; Type: TABLE; Schema: public; Owner: - -- Name: checklist_items; Type: TABLE; Schema: public; Owner: -
-- --
@ -3083,6 +3116,13 @@ ALTER TABLE ONLY public.asset_text_data ALTER COLUMN id SET DEFAULT nextval('pub
ALTER TABLE ONLY public.assets ALTER COLUMN id SET DEFAULT nextval('public.assets_id_seq'::regclass); ALTER TABLE ONLY public.assets ALTER COLUMN id SET DEFAULT nextval('public.assets_id_seq'::regclass);
--
-- Name: bmt_filters id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.bmt_filters ALTER COLUMN id SET DEFAULT nextval('public.bmt_filters_id_seq'::regclass);
-- --
-- Name: checklist_items id; Type: DEFAULT; Schema: public; Owner: - -- Name: checklist_items id; Type: DEFAULT; Schema: public; Owner: -
-- --
@ -3672,6 +3712,14 @@ ALTER TABLE ONLY public.assets
ADD CONSTRAINT assets_pkey PRIMARY KEY (id); ADD CONSTRAINT assets_pkey PRIMARY KEY (id);
--
-- Name: bmt_filters bmt_filters_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.bmt_filters
ADD CONSTRAINT bmt_filters_pkey PRIMARY KEY (id);
-- --
-- Name: checklist_items checklist_items_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- Name: checklist_items checklist_items_pkey; Type: CONSTRAINT; Schema: public; Owner: -
-- --
@ -4427,6 +4475,13 @@ CREATE INDEX index_assets_on_last_modified_by_id ON public.assets USING btree (l
CREATE INDEX index_assets_on_team_id ON public.assets USING btree (team_id); CREATE INDEX index_assets_on_team_id ON public.assets USING btree (team_id);
--
-- Name: index_bmt_filters_on_created_by_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_bmt_filters_on_created_by_id ON public.bmt_filters USING btree (created_by_id);
-- --
-- Name: index_checklist_items_on_checklist_id; Type: INDEX; Schema: public; Owner: - -- Name: index_checklist_items_on_checklist_id; Type: INDEX; Schema: public; Owner: -
-- --
@ -7147,6 +7202,14 @@ ALTER TABLE ONLY public.protocols
ADD CONSTRAINT fk_rails_dcb4ab6aa9 FOREIGN KEY (parent_id) REFERENCES public.protocols(id); ADD CONSTRAINT fk_rails_dcb4ab6aa9 FOREIGN KEY (parent_id) REFERENCES public.protocols(id);
--
-- Name: bmt_filters fk_rails_de5b654b84; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.bmt_filters
ADD CONSTRAINT fk_rails_de5b654b84 FOREIGN KEY (created_by_id) REFERENCES public.users(id);
-- --
-- Name: my_modules fk_rails_e21638fa54; Type: FK CONSTRAINT; Schema: public; Owner: - -- Name: my_modules fk_rails_e21638fa54; Type: FK CONSTRAINT; Schema: public; Owner: -
-- --
@ -7504,6 +7567,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20210715125349'), ('20210715125349'),
('20210716124649'), ('20210716124649'),
('20210720112050'), ('20210720112050'),
('20210812095254'); ('20210812095254'),
('20210825112050');