feat: integrate policy checks for feature enablement in calendar, folder, and plugins settings
This commit is contained in:
@@ -129,8 +129,24 @@ export async function POST(request: NextRequest) {
|
|||||||
const filteredSettings = { ...settings };
|
const filteredSettings = { ...settings };
|
||||||
for (const key of Object.keys(filteredSettings)) {
|
for (const key of Object.keys(filteredSettings)) {
|
||||||
const restriction = policy.restrictions[key];
|
const restriction = policy.restrictions[key];
|
||||||
if (restriction?.locked) {
|
if (!restriction) continue;
|
||||||
|
if (restriction.locked) {
|
||||||
delete filteredSettings[key];
|
delete filteredSettings[key];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const value = filteredSettings[key];
|
||||||
|
if (restriction.allowedValues && restriction.allowedValues.length > 0) {
|
||||||
|
if (!restriction.allowedValues.includes(value)) {
|
||||||
|
delete filteredSettings[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (typeof value === 'number') {
|
||||||
|
if (restriction.min !== undefined && value < restriction.min) {
|
||||||
|
delete filteredSettings[key];
|
||||||
|
}
|
||||||
|
if (restriction.max !== undefined && value > restriction.max) {
|
||||||
|
delete filteredSettings[key];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
import { useCalendarStore, CalendarViewMode } from '@/stores/calendar-store';
|
import { useCalendarStore, CalendarViewMode } from '@/stores/calendar-store';
|
||||||
import { useSettingsStore } from '@/stores/settings-store';
|
import { useSettingsStore } from '@/stores/settings-store';
|
||||||
|
import { usePolicyStore } from '@/stores/policy-store';
|
||||||
import { SettingsSection, SettingItem, Select, RadioGroup, ToggleSwitch } from './settings-section';
|
import { SettingsSection, SettingItem, Select, RadioGroup, ToggleSwitch } from './settings-section';
|
||||||
|
|
||||||
export function CalendarSettings() {
|
export function CalendarSettings() {
|
||||||
@@ -20,6 +21,7 @@ export function CalendarSettings() {
|
|||||||
showTasksOnCalendar,
|
showTasksOnCalendar,
|
||||||
updateSetting,
|
updateSetting,
|
||||||
} = useSettingsStore();
|
} = useSettingsStore();
|
||||||
|
const { isFeatureEnabled } = usePolicyStore();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsSection title={t('title')}>
|
<SettingsSection title={t('title')}>
|
||||||
@@ -78,6 +80,8 @@ export function CalendarSettings() {
|
|||||||
/>
|
/>
|
||||||
</SettingItem>
|
</SettingItem>
|
||||||
|
|
||||||
|
{isFeatureEnabled('calendarTasksEnabled') && (
|
||||||
|
<>
|
||||||
<SettingItem
|
<SettingItem
|
||||||
label={t('enable_tasks')}
|
label={t('enable_tasks')}
|
||||||
description={t('enable_tasks_desc')}
|
description={t('enable_tasks_desc')}
|
||||||
@@ -99,6 +103,8 @@ export function CalendarSettings() {
|
|||||||
/>
|
/>
|
||||||
</SettingItem>
|
</SettingItem>
|
||||||
)}
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { useTranslations } from 'next-intl';
|
|||||||
import { useEmailStore } from '@/stores/email-store';
|
import { useEmailStore } from '@/stores/email-store';
|
||||||
import { useAuthStore } from '@/stores/auth-store';
|
import { useAuthStore } from '@/stores/auth-store';
|
||||||
import { useSettingsStore } from '@/stores/settings-store';
|
import { useSettingsStore } from '@/stores/settings-store';
|
||||||
|
import { usePolicyStore } from '@/stores/policy-store';
|
||||||
import { toast } from '@/stores/toast-store';
|
import { toast } from '@/stores/toast-store';
|
||||||
import { SettingsSection, SettingItem, Select } from './settings-section';
|
import { SettingsSection, SettingItem, Select } from './settings-section';
|
||||||
import {
|
import {
|
||||||
@@ -100,6 +101,8 @@ export function FolderSettings() {
|
|||||||
const { client } = useAuthStore();
|
const { client } = useAuthStore();
|
||||||
const { mailboxes, createMailbox, renameMailbox, deleteMailbox, setMailboxRole } = useEmailStore();
|
const { mailboxes, createMailbox, renameMailbox, deleteMailbox, setMailboxRole } = useEmailStore();
|
||||||
const { folderIcons, setFolderIcon } = useSettingsStore();
|
const { folderIcons, setFolderIcon } = useSettingsStore();
|
||||||
|
const { isFeatureEnabled } = usePolicyStore();
|
||||||
|
const folderIconsAllowed = isFeatureEnabled('folderIconsEnabled');
|
||||||
|
|
||||||
const [isCreating, setIsCreating] = useState(false);
|
const [isCreating, setIsCreating] = useState(false);
|
||||||
const [creatingParentId, setCreatingParentId] = useState<string | null>(null);
|
const [creatingParentId, setCreatingParentId] = useState<string | null>(null);
|
||||||
@@ -380,22 +383,31 @@ export function FolderSettings() {
|
|||||||
<span className="w-4.5 flex-shrink-0" />
|
<span className="w-4.5 flex-shrink-0" />
|
||||||
)}
|
)}
|
||||||
<div className="relative flex-shrink-0">
|
<div className="relative flex-shrink-0">
|
||||||
<button
|
{folderIconsAllowed ? (
|
||||||
onClick={() => setIconPickerId(iconPickerId === mb.id ? null : mb.id)}
|
<button
|
||||||
className={cn(
|
onClick={() => setIconPickerId(iconPickerId === mb.id ? null : mb.id)}
|
||||||
"p-1 rounded-md transition-colors",
|
className={cn(
|
||||||
iconPickerId === mb.id
|
"p-1 rounded-md transition-colors",
|
||||||
? "bg-accent"
|
iconPickerId === mb.id
|
||||||
: "hover:bg-accent"
|
? "bg-accent"
|
||||||
)}
|
: "hover:bg-accent"
|
||||||
title={t('change_icon')}
|
)}
|
||||||
>
|
title={t('change_icon')}
|
||||||
<Icon className={cn(
|
>
|
||||||
"w-4 h-4",
|
<Icon className={cn(
|
||||||
mb.role ? "text-primary" : "text-muted-foreground"
|
"w-4 h-4",
|
||||||
)} />
|
mb.role ? "text-primary" : "text-muted-foreground"
|
||||||
</button>
|
)} />
|
||||||
{iconPickerId === mb.id && (
|
</button>
|
||||||
|
) : (
|
||||||
|
<span className="p-1">
|
||||||
|
<Icon className={cn(
|
||||||
|
"w-4 h-4",
|
||||||
|
mb.role ? "text-primary" : "text-muted-foreground"
|
||||||
|
)} />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{folderIconsAllowed && iconPickerId === mb.id && (
|
||||||
<IconPicker
|
<IconPicker
|
||||||
currentIcon={getIconName(mb)}
|
currentIcon={getIconName(mb)}
|
||||||
onSelect={(iconName) => {
|
onSelect={(iconName) => {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import { useState, useRef } from 'react';
|
import { useState, useRef } from 'react';
|
||||||
import { usePluginStore } from '@/stores/plugin-store';
|
import { usePluginStore } from '@/stores/plugin-store';
|
||||||
|
import { usePolicyStore } from '@/stores/policy-store';
|
||||||
import { SettingsSection, SettingItem, ToggleSwitch } from './settings-section';
|
import { SettingsSection, SettingItem, ToggleSwitch } from './settings-section';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { Upload, Trash2, AlertTriangle, Puzzle } from 'lucide-react';
|
import { Upload, Trash2, AlertTriangle, Puzzle } from 'lucide-react';
|
||||||
@@ -19,10 +20,15 @@ const STATUS_COLORS: Record<PluginStatus, string> = {
|
|||||||
|
|
||||||
export function PluginsSettings() {
|
export function PluginsSettings() {
|
||||||
const { plugins, installPlugin, uninstallPlugin, enablePlugin, disablePlugin, updatePluginSettings } = usePluginStore();
|
const { plugins, installPlugin, uninstallPlugin, enablePlugin, disablePlugin, updatePluginSettings } = usePluginStore();
|
||||||
|
const { isFeatureEnabled } = usePolicyStore();
|
||||||
const [isUploading, setIsUploading] = useState(false);
|
const [isUploading, setIsUploading] = useState(false);
|
||||||
const [expandedPlugin, setExpandedPlugin] = useState<string | null>(null);
|
const [expandedPlugin, setExpandedPlugin] = useState<string | null>(null);
|
||||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
if (!isFeatureEnabled('pluginsEnabled')) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const handleUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const file = e.target.files?.[0];
|
const file = e.target.files?.[0];
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
|||||||
Reference in New Issue
Block a user