mirror of
https://github.com/inventree/InvenTree.git
synced 2025-09-13 22:21:37 +00:00
[Refactor] Notification plugins (#9735)
* Refactor notification concept - Notifications handled by plugins * Cleanup * Only send email if template provided in context * Logic cleanup * Fix log_error call * Refactor error logging - Ensure plugin slug is correctly attached - Consistent format - Logic fixes * More robust plugin lookup * Refactor calls to tringger_notification * Tweak for build stock notification * Low stock notification refactor - Actually *use* the notification system - Fix for email template * Check stock only when build is issued * Updated documentation * Add PluginUserSetting class - Allows plugins to define per-user settings * Add API endpoints for PluginUserSetting model * Placeholder for user-plugin-settings page * Refactoring frontend code * Placeholder panel * Adds user interface for changing user-specific plugin settings * Tweaks * Remove old model * Update documentation * Playwright tests * Update API version * Fix unit test * Fix removed arg * Fixes for email notifications - Track status of sending notifications - Add helper "activate" method for plugin class - Update unit tests * Fix barcode tests * More unit test fixes * Test fixes * Fix for settings models with extra fields * Enhance unit test * Remove old test file * Check for null target_fnc * Improve DB query efficiency - Provide a flat list of active keys to plugin.is_active - Prevents DB fetching (in certain circumstances) - Add registry.active_plugins() method * Bump query limit up for test - In practice, this API endpoint is ~10 queries * Handle potential errors * Increase query limit for API test * Increase query limit for some tests * Bump API version * Tweak unit test * Tweak unit test * Increased allowed queries * fix user plugin settings * Fix for unit test * Update debug msg * Tweak API * Fix endpoint * Remove "active plugin keys" code * Restore previous behaviour * Fix unit tests * Tweak unit test * Update src/backend/InvenTree/build/tasks.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/backend/InvenTree/plugin/base/integration/NotificationMixin.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Func updates * Format * Add notification settings * Refactor plugin settings groups * Fix func type * Adjust message * Additional unit tests * Additional playwright tests * Additional playwright test --------- Co-authored-by: Matthias Mair <code@mjmair.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -65,6 +65,47 @@ test('Plugins - Settings', async ({ browser, request }) => {
|
||||
await page.getByText('Mouser Electronics').click();
|
||||
});
|
||||
|
||||
test('Plugins - User Settings', async ({ browser, request }) => {
|
||||
const page = await doCachedLogin(browser);
|
||||
|
||||
// Ensure that the SampleIntegration plugin is enabled
|
||||
await setPluginState({
|
||||
request,
|
||||
plugin: 'sample',
|
||||
state: true
|
||||
});
|
||||
|
||||
// Navigate to user settings
|
||||
await navigate(page, 'settings/user/');
|
||||
await loadTab(page, 'Plugin Settings');
|
||||
|
||||
// User settings for the "Sample Plugin" should be visible
|
||||
await page.getByRole('button', { name: 'Sample Plugin' }).click();
|
||||
|
||||
await page.getByText('User Setting 1').waitFor();
|
||||
await page.getByText('User Setting 2').waitFor();
|
||||
await page.getByText('User Setting 3').waitFor();
|
||||
|
||||
// Check for expected setting options
|
||||
await page.getByLabel('edit-setting-USER_SETTING_3').click();
|
||||
|
||||
const val = await page.getByLabel('choice-field-value').inputValue();
|
||||
|
||||
await page.getByLabel('choice-field-value').click();
|
||||
|
||||
await page.getByRole('option', { name: 'Choice X' }).waitFor();
|
||||
await page.getByRole('option', { name: 'Choice Y' }).waitFor();
|
||||
await page.getByRole('option', { name: 'Choice Z' }).waitFor();
|
||||
|
||||
// Change the value of USER_SETTING_3
|
||||
await page
|
||||
.getByRole('option', { name: val == 'Choice X' ? 'Choice Z' : 'Choice X' })
|
||||
.click();
|
||||
await page.getByRole('button', { name: 'Submit' }).click();
|
||||
|
||||
await page.getByText('Setting USER_SETTING_3 updated successfully').waitFor();
|
||||
});
|
||||
|
||||
// Test base plugin functionality
|
||||
test('Plugins - Functionality', async ({ browser }) => {
|
||||
// Navigate and select the plugin
|
||||
|
@@ -2,7 +2,7 @@ import { expect, test } from './baseFixtures.js';
|
||||
import { apiUrl } from './defaults.js';
|
||||
import { getRowFromCell, loadTab, navigate } from './helpers.js';
|
||||
import { doCachedLogin } from './login.js';
|
||||
import { setSettingState } from './settings.js';
|
||||
import { setPluginState, setSettingState } from './settings.js';
|
||||
|
||||
/**
|
||||
* Adjust language and color settings
|
||||
@@ -80,6 +80,97 @@ test('Settings - User theme', async ({ browser }) => {
|
||||
await page.getByLabel('#228be6').click();
|
||||
});
|
||||
|
||||
test('Settings - User', async ({ browser }) => {
|
||||
const page = await doCachedLogin(browser, {
|
||||
username: 'allaccess',
|
||||
password: 'nolimits',
|
||||
url: 'settings/user/'
|
||||
});
|
||||
|
||||
await loadTab(page, 'Account');
|
||||
await page.getByText('Account Details').waitFor();
|
||||
await page.getByText('Profile Details').waitFor();
|
||||
|
||||
await loadTab(page, 'Security');
|
||||
await page.getByRole('button', { name: 'Single Sign On' }).waitFor();
|
||||
await page.getByRole('button', { name: 'Access Tokens' }).waitFor();
|
||||
|
||||
await loadTab(page, 'Display Options');
|
||||
await page
|
||||
.getByText('The navbar position is fixed to the top of the screen')
|
||||
.waitFor();
|
||||
await page.getByText('Escape Key Closes Forms').waitFor();
|
||||
|
||||
await loadTab(page, 'Search');
|
||||
await page.getByText('Whole Word Search').waitFor();
|
||||
await page.getByText('Hide Unavailable Stock Items').waitFor();
|
||||
|
||||
await loadTab(page, 'Notifications');
|
||||
await page
|
||||
.getByRole('button', { name: 'InvenTree Email Notifications' })
|
||||
.waitFor();
|
||||
|
||||
await loadTab(page, 'Reporting');
|
||||
await page.getByText('Inline report display').waitFor();
|
||||
|
||||
await loadTab(page, 'Plugin Settings');
|
||||
await page
|
||||
.getByRole('button', { name: 'InvenTree Email Notifications' })
|
||||
.waitFor();
|
||||
});
|
||||
|
||||
test('Settings - Global', async ({ browser, request }) => {
|
||||
const page = await doCachedLogin(browser, {
|
||||
username: 'steven',
|
||||
password: 'wizardstaff',
|
||||
url: 'settings/system/'
|
||||
});
|
||||
|
||||
// Ensure the "slack" notification plugin is enabled
|
||||
// This is to ensure it is visible in the "notification" settings tab
|
||||
await setPluginState({
|
||||
request,
|
||||
plugin: 'inventree-slack-notification',
|
||||
state: true
|
||||
});
|
||||
|
||||
await loadTab(page, 'Server');
|
||||
await loadTab(page, 'Authentication');
|
||||
await loadTab(page, 'Barcodes');
|
||||
await loadTab(page, 'Pricing');
|
||||
await loadTab(page, 'Parts');
|
||||
await loadTab(page, 'Stock');
|
||||
|
||||
await loadTab(page, 'Notifications');
|
||||
await page
|
||||
.getByText(
|
||||
'The settings below are specific to each available notification method'
|
||||
)
|
||||
.waitFor();
|
||||
|
||||
await page
|
||||
.getByRole('button', { name: 'InvenTree Slack Notifications' })
|
||||
.click();
|
||||
await page.getByText('Slack incoming webhook url').waitFor();
|
||||
await page
|
||||
.getByText('URL that is used to send messages to a slack channel')
|
||||
.waitFor();
|
||||
|
||||
await loadTab(page, 'Plugin Settings');
|
||||
await page
|
||||
.getByText('The settings below are specific to each available plugin')
|
||||
.waitFor();
|
||||
await page
|
||||
.getByRole('button', { name: 'InvenTree Barcodes Provides' })
|
||||
.waitFor();
|
||||
await page
|
||||
.getByRole('button', { name: 'InvenTree PDF label printer' })
|
||||
.waitFor();
|
||||
await page
|
||||
.getByRole('button', { name: 'InvenTree Slack Notifications' })
|
||||
.waitFor();
|
||||
});
|
||||
|
||||
test('Settings - Admin', async ({ browser }) => {
|
||||
// Note here we login with admin access
|
||||
const page = await doCachedLogin(browser, {
|
||||
|
Reference in New Issue
Block a user