diff --git a/Gemfile.lock b/Gemfile.lock
index 4606b128b..3f76d9e08 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -269,6 +269,8 @@ GEM
net-smtp (0.3.3)
net-protocol
nio4r (2.5.8)
+ nokogiri (1.14.3-x86_64-darwin)
+ racc (~> 1.4)
nokogiri (1.14.3-x86_64-linux)
racc (~> 1.4)
oauth2 (1.4.4)
@@ -524,6 +526,7 @@ GEM
zeitwerk (2.6.7)
PLATFORMS
+ x86_64-darwin-21
x86_64-linux
DEPENDENCIES
diff --git a/app/frontend/src/javascript/controllers/projects.js b/app/frontend/src/javascript/controllers/projects.js
index 6aa7d8112..f09615e07 100644
--- a/app/frontend/src/javascript/controllers/projects.js
+++ b/app/frontend/src/javascript/controllers/projects.js
@@ -281,8 +281,8 @@ class ProjectsController {
/**
* Controller used on projects listing page
*/
-Application.Controllers.controller('ProjectsController', ['$scope', '$state', 'Project', 'machinesPromise', 'themesPromise', 'componentsPromise', 'paginationService', 'OpenlabProject', '$window', 'growl', '_t', '$location', '$timeout', 'settingsPromise', 'openLabActive',
- function ($scope, $state, Project, machinesPromise, themesPromise, componentsPromise, paginationService, OpenlabProject, $window, growl, _t, $location, $timeout, settingsPromise, openLabActive) {
+Application.Controllers.controller('ProjectsController', ['$scope', '$state', 'Project', 'machinesPromise', 'themesPromise', 'componentsPromise', 'paginationService', 'OpenlabProject', '$window', 'growl', '_t', '$location', '$timeout', 'settingsPromise', 'openLabActive', 'Member', 'Diacritics',
+ function ($scope, $state, Project, machinesPromise, themesPromise, componentsPromise, paginationService, OpenlabProject, $window, growl, _t, $location, $timeout, settingsPromise, openLabActive, Member, Diacritics) {
/* PRIVATE STATIC CONSTANTS */
// Number of projects added to the page when the user clicks on 'load more projects'
@@ -294,12 +294,18 @@ Application.Controllers.controller('ProjectsController', ['$scope', '$state', 'P
// Fab-manager's instance ID in the openLab network
$scope.openlabAppId = settingsPromise.openlab_app_id;
+ $scope.memberFilterPresence = settingsPromise.projects_list_member_filter_presence !== 'false';
+
// Is openLab enabled on the instance?
$scope.openlab = {
projectsActive: openLabActive.isPresent,
searchOverWholeNetwork: settingsPromise.openlab_default === 'true'
};
+ if (!$scope.memberFilterPresence) {
+ $location.$$search.member_id = '';
+ }
+
// default search parameters
$scope.search = {
q: ($location.$$search.q || ''),
@@ -307,7 +313,24 @@ Application.Controllers.controller('ProjectsController', ['$scope', '$state', 'P
machine_id: (parseInt($location.$$search.machine_id) || undefined),
component_id: (parseInt($location.$$search.component_id) || undefined),
theme_id: (parseInt($location.$$search.theme_id) || undefined),
- status_id: (parseInt($location.$$search.status_id) || undefined)
+ status_id: (parseInt($location.$$search.status_id) || undefined),
+ member_id: (parseInt($location.$$search.member_id) || undefined)
+ };
+
+ $scope.autoCompleteMemberName = function (nameLookup) {
+ if (!nameLookup) {
+ return;
+ }
+ $scope.isLoadingMembers = true;
+ const asciiName = Diacritics.remove(nameLookup);
+
+ const q = { query: asciiName };
+
+ Member.search(q, function (users) {
+ $scope.matchingMembers = users;
+ $scope.isLoadingMembers = false;
+ }
+ , function (error) { console.error(error); });
};
// list of projects to display
@@ -361,6 +384,7 @@ Application.Controllers.controller('ProjectsController', ['$scope', '$state', 'P
$scope.search.component_id = undefined;
$scope.search.theme_id = undefined;
$scope.search.status_id = undefined;
+ $scope.search.member_id = undefined;
$scope.$apply();
$scope.setUrlQueryParams($scope.search);
$scope.triggerSearch();
@@ -420,6 +444,16 @@ Application.Controllers.controller('ProjectsController', ['$scope', '$state', 'P
updateUrlParam('component_id', search.component_id);
updateUrlParam('machine_id', search.machine_id);
updateUrlParam('status_id', search.status_id);
+ updateUrlParam('member_id', search.member_id);
+ return true;
+ };
+
+ $scope.setSearchMemberId = function (searchMember) {
+ if (searchMember) {
+ $scope.search.member_id = searchMember.id;
+ } else {
+ $scope.search.member_id = undefined;
+ }
return true;
};
@@ -450,6 +484,11 @@ Application.Controllers.controller('ProjectsController', ['$scope', '$state', 'P
} else {
$scope.openlab.searchOverWholeNetwork = $scope.openlab.projectsActive;
}
+ if ($location.$$search.member_id && $scope.memberFilterPresence) {
+ Member.get({ id: $location.$$search.member_id }, function (member) {
+ $scope.searchMember = member;
+ });
+ }
return $scope.triggerSearch();
};
diff --git a/app/frontend/src/javascript/models/setting.ts b/app/frontend/src/javascript/models/setting.ts
index 27f84db14..37ffd2fdb 100644
--- a/app/frontend/src/javascript/models/setting.ts
+++ b/app/frontend/src/javascript/models/setting.ts
@@ -198,7 +198,8 @@ export const fabHubSettings = [
export const projectsSettings = [
'allowed_cad_extensions',
'allowed_cad_mime_types',
- 'disqus_shortname'
+ 'disqus_shortname',
+ 'projects_list_member_filter_presence'
] as const;
export const prepaidPacksSettings = [
diff --git a/app/frontend/src/javascript/router.js b/app/frontend/src/javascript/router.js
index 26ce00a93..a400a3323 100644
--- a/app/frontend/src/javascript/router.js
+++ b/app/frontend/src/javascript/router.js
@@ -301,7 +301,7 @@ angular.module('application.router', ['ui.router'])
themesPromise: ['Theme', function (Theme) { return Theme.query().$promise; }],
componentsPromise: ['Component', function (Component) { return Component.query().$promise; }],
machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }],
- settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: "['openlab_app_id', 'openlab_default']" }).$promise; }],
+ settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: "['openlab_app_id', 'openlab_default', 'projects_list_member_filter_presence']" }).$promise; }],
openLabActive: ['Setting', function (Setting) { return Setting.isPresent({ name: 'openlab_app_secret' }).$promise; }]
}
})
diff --git a/app/frontend/templates/admin/projects/settings.html b/app/frontend/templates/admin/projects/settings.html
index 73bd51897..e7757928f 100644
--- a/app/frontend/templates/admin/projects/settings.html
+++ b/app/frontend/templates/admin/projects/settings.html
@@ -95,3 +95,18 @@
+
+
+
+ {{ 'app.admin.projects.settings.filters' }}
+
+
+
diff --git a/app/frontend/templates/projects/index.html b/app/frontend/templates/projects/index.html
index 22d8f8143..1ee31bddf 100644
--- a/app/frontend/templates/projects/index.html
+++ b/app/frontend/templates/projects/index.html
@@ -65,6 +65,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/helpers/settings_helper.rb b/app/helpers/settings_helper.rb
index 1520bd44d..5dc8cea10 100644
--- a/app/helpers/settings_helper.rb
+++ b/app/helpers/settings_helper.rb
@@ -196,6 +196,7 @@ module SettingsHelper
events_banner_cta_active
events_banner_cta_label
events_banner_cta_url
+ projects_list_member_filter_presence
].freeze
end
# rubocop:enable Metrics/ModuleLength
diff --git a/app/policies/setting_policy.rb b/app/policies/setting_policy.rb
index 1593beb55..1e11dfe90 100644
--- a/app/policies/setting_policy.rb
+++ b/app/policies/setting_policy.rb
@@ -46,7 +46,7 @@ class SettingPolicy < ApplicationPolicy
external_id machines_banner_active machines_banner_text machines_banner_cta_active machines_banner_cta_label
machines_banner_cta_url trainings_banner_active trainings_banner_text trainings_banner_cta_active trainings_banner_cta_label
trainings_banner_cta_url events_banner_active events_banner_text events_banner_cta_active events_banner_cta_label
- events_banner_cta_url]
+ events_banner_cta_url projects_list_member_filter_presence]
end
##
diff --git a/app/services/project_service.rb b/app/services/project_service.rb
index 823d9365d..3e01d5c16 100644
--- a/app/services/project_service.rb
+++ b/app/services/project_service.rb
@@ -23,6 +23,14 @@ class ProjectService
records = records.with_theme(query_params['theme_id']) if query_params['theme_id'].present?
records = records.with_space(query_params['space_id']) if query_params['space_id'].present?
records = records.with_status(query_params['status_id']) if query_params['status_id'].present?
+
+ if query_params['member_id'].present?
+ member = User.find(query_params['member_id'])
+ if member
+ records = records.where(id: Project.user_projects(member.statistic_profile.id)).or(Project.where(id: Project.collaborations(member.id)))
+ end
+ end
+
records = if query_params['q'].present?
records.search(query_params['q'])
else
diff --git a/app/views/application/index.html.erb b/app/views/application/index.html.erb
index 159ec0737..87396cdcf 100644
--- a/app/views/application/index.html.erb
+++ b/app/views/application/index.html.erb
@@ -61,6 +61,9 @@
buttons: <%= I18n.t('app.shared.buttons').to_json.html_safe %>,
messages: <%= I18n.t('app.shared.messages').to_json.html_safe %>
}
+ },
+ date: {
+ month_names: <%= I18n.t('date.month_names').to_json.html_safe %>
}
};
Fablab.weekStartingDay = <%= Date.parse(Rails.application.secrets.week_starting_day).strftime('%w') %>;
diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml
index 8714ac56d..8d211c2b0 100644
--- a/config/locales/app.admin.en.yml
+++ b/config/locales/app.admin.en.yml
@@ -445,6 +445,7 @@ en:
open_lab_app_secret: "Secret"
openlab_default_info_html: "In the projects gallery, visitors can switch between two views: all shared projects from the whole OpenLab network, or only the projects documented in your Fab Lab.
Here, you can choose which view is shown by default."
default_to_openlab: "Display OpenLab by default"
+ filters: Projects list filters
projects_setting:
add: "Add"
actions_controls: "Actions"
@@ -1773,6 +1774,7 @@ en:
extended_prices_in_same_day: "Extended prices in the same day"
public_registrations: "Public registrations"
show_username_in_admin_list: "Show the username in the list"
+ projects_list_member_filter_presence: "Presence of member filter on projects list"
overlapping_options:
training_reservations: "Trainings"
machine_reservations: "Machines"
diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml
index e7082ef58..003ab199c 100644
--- a/config/locales/app.admin.fr.yml
+++ b/config/locales/app.admin.fr.yml
@@ -445,6 +445,7 @@ fr:
open_lab_app_secret: "Secret"
openlab_default_info_html: "Dans la galerie de projets, les visiteurs peuvent choisir entre deux vues : tous les projets de l'ensemble du réseau OpenLab, ou uniquement les projets documentés dans votre Fab Lab.
Ici, vous pouvez choisir quelle vue est affichée par défaut."
default_to_openlab: "Afficher OpenLab par défaut"
+ filters: Filtres de la vue liste
projects_setting:
add: "Ajouter"
actions_controls: "Actions"
@@ -1773,6 +1774,7 @@ fr:
extended_prices_in_same_day: "Prix étendus le même jour"
public_registrations: "Inscriptions publiques"
show_username_in_admin_list: "Afficher le nom d'utilisateur dans la liste"
+ projects_list_member_filter_presence: "Présence du filtre par membre dans la vue liste des projets"
overlapping_options:
training_reservations: "Formations"
machine_reservations: "Machines"
diff --git a/config/locales/app.public.en.yml b/config/locales/app.public.en.yml
index 7dfc61f69..389775687 100644
--- a/config/locales/app.public.en.yml
+++ b/config/locales/app.public.en.yml
@@ -183,6 +183,7 @@ en:
all_materials: "All materials"
load_next_projects: "Load next projects"
rough_draft: "Rough draft"
+ filter_by_member: "Filter by member"
status_filter:
all_statuses: "All statuses"
select_status: "Select a status"
diff --git a/config/locales/app.public.fr.yml b/config/locales/app.public.fr.yml
index 09a07a116..82a6b7f15 100644
--- a/config/locales/app.public.fr.yml
+++ b/config/locales/app.public.fr.yml
@@ -183,6 +183,7 @@ fr:
all_materials: "Tous les matériaux"
load_next_projects: "Charger les projets suivants"
rough_draft: "Brouillon"
+ filter_by_member: "Filter par membre"
status_filter:
all_statuses: "Tous les statuts"
select_status: "Sélectionnez un statut"
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 3bd7aae37..7c3443d36 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -697,6 +697,7 @@ en:
trainings_authorization_validity_duration: "Trainings validity period duration"
trainings_invalidation_rule: "Trainings automatic invalidation"
trainings_invalidation_rule_period: "Grace period before invalidating a training"
+ projects_list_member_filter_presence: "Presence of member filter on projects list"
#statuses of projects
statuses:
new: "New"
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index 5331975c3..af049d102 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -697,6 +697,7 @@ fr:
trainings_authorization_validity_duration: "Durée de la période de validité des formations"
trainings_invalidation_rule: "Invalidation automatique des formations"
trainings_invalidation_rule_period: "Période de grâce avant d'invalider une formation"
+ projects_list_member_filter_presence: "Présence du filtre par membre dans la vue liste des projets"
#statuses of projects
statuses:
new: "Nouveau"
diff --git a/db/seeds/settings.rb b/db/seeds/settings.rb
index 4df47c23c..28beafcda 100644
--- a/db/seeds/settings.rb
+++ b/db/seeds/settings.rb
@@ -728,3 +728,5 @@ Setting.set('accounting_Error_code', 'ERROR') unless Setting.find_by(name: 'acco
Setting.set('accounting_Error_label', 'Erroneous invoices to refund') unless Setting.find_by(name: 'accounting_Error_label').try(:value)
Setting.set('external_id', false) unless Setting.find_by(name: 'external_id').try(:value)
+
+Setting.set('projects_list_member_filter_presence', false) unless Setting.find_by(name: 'projects_list_member_filter_presence')
diff --git a/test/fixtures/history_values.yml b/test/fixtures/history_values.yml
index 4ce437af6..0ba0f4645 100644
--- a/test/fixtures/history_values.yml
+++ b/test/fixtures/history_values.yml
@@ -852,3 +852,10 @@ history_value_100:
updated_at: 2023-04-05 09:16:08.000511500 Z
invoicing_profile_id: 1
+history_value_103:
+ id: 103
+ setting_id: 102
+ value: 'false'
+ created_at: 2023-04-05 09:16:08.000511500 Z
+ updated_at: 2023-04-05 09:16:08.000511500 Z
+ invoicing_profile_id: 1
\ No newline at end of file
diff --git a/test/fixtures/settings.yml b/test/fixtures/settings.yml
index eb21fa7f8..7b26448ac 100644
--- a/test/fixtures/settings.yml
+++ b/test/fixtures/settings.yml
@@ -586,3 +586,9 @@ setting_99:
name: home_css
created_at: 2023-04-05 09:16:08.000511500 Z
updated_at: 2023-04-05 09:16:08.000511500 Z
+
+setting_102:
+ id: 102
+ name: projects_list_member_filter_presence
+ created_at: 2023-04-05 09:16:08.000511500 Z
+ updated_at: 2023-04-05 09:16:08.000511500 Z
diff --git a/test/frontend/__fixtures__/settings.ts b/test/frontend/__fixtures__/settings.ts
index 03dd134be..246191ea4 100644
--- a/test/frontend/__fixtures__/settings.ts
+++ b/test/frontend/__fixtures__/settings.ts
@@ -825,6 +825,12 @@ export const settings: Array = [
value: 'https://www.sleede.com/',
last_update: '2022-12-23T14:39:12+0100',
localized: 'Url'
+ },
+ {
+ name: 'projects_list_member_filter_presence',
+ value: 'false',
+ last_update: '2022-12-23T14:39:12+0100',
+ localized: 'Projects list member filter presence'
}
];