feat(domain,application,infrastructure,backend,web-server,app-tauri,frontend): bibliothèque d'icônes projet personnalisées importées par l'utilisateur — #358 (QA verte)
domain: variante ProjectIconSet::Custom, métadonnées CustomProjectIconAsset (id opaque, media type png/jpeg/webp, byte_size, dimensions décodées, sha256, nom de fichier original sans chemin, created_at), CustomProjectIconContent et port CustomProjectIconAssetStore (list/read/exists/create/delete) avec CustomProjectIconStoreError dédiée. application: use case project_icon_assets — import validé png/jpeg/webp avec rejet du contenu SVG, dimensionnement et digest sha256, bibliothèque partagée à l'instance indépendante de tout projet, suppression refusée tant que l'asset est référencé par un projet. infrastructure: store fichier store/project_icon_asset.rs — index canonique + octets, création atomique sous extension validée. backend/web-server: contrat HTTP /api/project-icon-assets (GET liste, POST import, GET lecture, GET /usage, DELETE) avec prévol OPTIONS et tests contrat incluant le rejet SVG. app-tauri: commandes import/list/read/get_usage/delete_custom_project_icon_asset exposées au frontend. frontend: port ProjectIconAssetGateway (list/import/delete/getUrl sans exposer de chemin filesystem), gateways http+mock avec tests, DI, section Icônes personnalisées du ProjectIconPicker (import fichier accept png/jpeg/webp, sélection role=option, suppression avec retrait de sélection, erreurs lisibles i18n FR/EN), tests projectIcons étendus. QA verte: contrats HTTP et Tauri identiques, suites cargo et npm ciblées vertes.
This commit is contained in:
@ -3358,6 +3358,88 @@ pub struct ProjectIconRefDto {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
/// Metadata for one user-imported icon, including live project usage.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CustomProjectIconAssetDto {
|
||||
/// Opaque stable asset id.
|
||||
pub id: String,
|
||||
/// Validated raster media type.
|
||||
pub media_type: String,
|
||||
/// Stored encoded byte count.
|
||||
pub byte_size: u64,
|
||||
/// Pixel width.
|
||||
pub width: u32,
|
||||
/// Pixel height.
|
||||
pub height: u32,
|
||||
/// SHA-256 digest.
|
||||
pub sha256: String,
|
||||
/// Original user-facing basename.
|
||||
pub original_filename: String,
|
||||
/// Creation time as epoch milliseconds.
|
||||
pub created_at: i64,
|
||||
/// Current number of registered projects using the asset.
|
||||
pub used_by_project_count: u64,
|
||||
}
|
||||
|
||||
impl From<application::CustomProjectIconAssetView> for CustomProjectIconAssetDto {
|
||||
fn from(value: application::CustomProjectIconAssetView) -> Self {
|
||||
Self {
|
||||
id: value.asset.id,
|
||||
media_type: value.asset.media_type,
|
||||
byte_size: value.asset.byte_size,
|
||||
width: value.asset.width,
|
||||
height: value.asset.height,
|
||||
sha256: value.asset.sha256,
|
||||
original_filename: value.asset.original_filename,
|
||||
created_at: value.asset.created_at,
|
||||
used_by_project_count: value.used_by_project_count,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Import payload shared by Tauri and HTTP JSON clients.
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
||||
pub struct ImportCustomProjectIconAssetRequestDto {
|
||||
/// User-facing source basename (paths are stripped server-side).
|
||||
pub original_filename: String,
|
||||
/// Claimed media type, verified against file bytes.
|
||||
pub media_type: String,
|
||||
/// Standard base64-encoded image bytes.
|
||||
pub data_base64: String,
|
||||
}
|
||||
|
||||
/// Tauri-safe read response; HTTP serves these bytes directly instead.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CustomProjectIconAssetContentDto {
|
||||
/// Metadata and usage.
|
||||
#[serde(flatten)]
|
||||
pub metadata: CustomProjectIconAssetDto,
|
||||
/// Standard base64-encoded image bytes.
|
||||
pub data_base64: String,
|
||||
}
|
||||
|
||||
/// Current usage for one custom icon.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CustomProjectIconUsageDto {
|
||||
/// Stable asset id.
|
||||
pub asset_id: String,
|
||||
/// Number of registered projects using it.
|
||||
pub used_by_project_count: u64,
|
||||
}
|
||||
|
||||
impl From<application::CustomProjectIconUsage> for CustomProjectIconUsageDto {
|
||||
fn from(value: application::CustomProjectIconUsage) -> Self {
|
||||
Self {
|
||||
asset_id: value.asset_id,
|
||||
used_by_project_count: value.used_by_project_count,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<domain::ProjectIconRef> for ProjectIconRefDto {
|
||||
fn from(value: domain::ProjectIconRef) -> Self {
|
||||
Self {
|
||||
|
||||
@ -21,30 +21,33 @@ use application::{
|
||||
ClearChatDraft, CloneOpenCodeProfileFromSeed, CloneProfileFromSeed, CloseProject, CloseTab,
|
||||
CloseTerminal, CloseTicketAssistant, ConfigureProfiles, ContextGuardUseCases,
|
||||
CreateAgentFromScratch, CreateAgentFromTemplate, CreateIssue, CreateLayout, CreateMemory,
|
||||
CreateProject, CreateSkill, CreateSprint, CreateTemplate, DeleteAgent, DeleteEmbedderProfile,
|
||||
DeleteIssue, DeleteLayout, DeleteMemory, DeleteModelArtifact, DeleteModelServer, DeleteProfile,
|
||||
DeleteSkill, DeleteSprint, DeleteTemplate, DescribeEmbedderEngines, DetectAgentDrift,
|
||||
DetectProfiles, DismissEmbedderSuggestion, EnsureLocalModelServer, ExecuteSlashCommand,
|
||||
FirstRunState, GcManagedTemp, GetAppExitWorkGuardState, GetLiveStateLean, GetMemory,
|
||||
GetProjectPermissions, GetProjectSystemPermissions, GetProjectWorkState, GitBranches,
|
||||
GitCheckout, GitCommit, GitGraph, GitInit, GitLog, GitStage, GitStatus, GitUnstage,
|
||||
HarvestMemoryFromTurn, HealthUseCase, ImportChatAttachments, InspectConversation,
|
||||
InstallPluginFromArchive, InstallPluginFromDirectory, JsonPluginManifestValidator, LaunchAgent,
|
||||
LaunchAgentInput, LinkIssues, ListAgents, ListAgentsInput, ListClaudeModels, ListCodexModels,
|
||||
ListDevices, ListEmbedderProfiles, ListIssues, ListLayouts, ListMemories, ListModelServers,
|
||||
ListOpenCodeProviders, ListPluginRuntimeContributions, ListPlugins, ListProfiles,
|
||||
ListProjectFiles, ListProjectPluginSettings, ListProjects, ListResumableAgents, ListSkills,
|
||||
ListSlashCommands, ListSprints, ListTemplates, LiveAgentRegistry, LiveSessions,
|
||||
LiveStateLeanProvider, LiveStateProvider, LiveStateReadProvider, LoadLayout,
|
||||
MarkIssueAttachmentSummarized, McpRuntime, McpToolPermissionCatalogue, MoveTabToNewWindow,
|
||||
MutateAgentPluginSkill, MutateAgentPluginTool, MutateLayout, OnnxModelView,
|
||||
OpenPluginLayoutWindow, OpenProject, OpenTerminal, OpenTicketAssistant, OrchestratorService,
|
||||
PairAttemptLimiter, PairDevice, PermissionProjectorRegistry, PluginCommandTasks,
|
||||
PluginConfigDocuments, PluginEventSubscriptions, PluginStorageAccess,
|
||||
PluginToolchainDiagnostics, PluginWorkspaceAccess, PluginWorkspaceExecTool,
|
||||
ProjectPluginResolver, ProposeContext, PurgeManagedTemp, QueryProjectStructure,
|
||||
ReadAgentContext, ReadChatDraft, ReadContext, ReadConversationPage, ReadIssue,
|
||||
ReadIssueAttachment, ReadIssueCarnet, ReadMcpToolPermissions, ReadMemory, ReadMemoryIndex,
|
||||
CreateProject, CreateSkill, CreateSprint, CreateTemplate, DeleteAgent,
|
||||
DeleteCustomProjectIconAsset, DeleteEmbedderProfile, DeleteIssue, DeleteLayout, DeleteMemory,
|
||||
DeleteModelArtifact, DeleteModelServer, DeleteProfile, DeleteSkill, DeleteSprint,
|
||||
DeleteTemplate, DescribeEmbedderEngines, DetectAgentDrift, DetectProfiles,
|
||||
DismissEmbedderSuggestion, EnsureLocalModelServer, ExecuteSlashCommand, FirstRunState,
|
||||
GcManagedTemp, GetAppExitWorkGuardState, GetCustomProjectIconAssetUsage, GetLiveStateLean,
|
||||
GetMemory, GetProjectPermissions, GetProjectSystemPermissions, GetProjectWorkState,
|
||||
GitBranches, GitCheckout, GitCommit, GitGraph, GitInit, GitLog, GitStage, GitStatus,
|
||||
GitUnstage, HarvestMemoryFromTurn, HealthUseCase, ImportChatAttachments,
|
||||
ImportCustomProjectIconAsset, InspectConversation, InstallPluginFromArchive,
|
||||
InstallPluginFromDirectory, JsonPluginManifestValidator, LaunchAgent, LaunchAgentInput,
|
||||
LinkIssues, ListAgents, ListAgentsInput, ListClaudeModels, ListCodexModels,
|
||||
ListCustomProjectIconAssets, ListDevices, ListEmbedderProfiles, ListIssues, ListLayouts,
|
||||
ListMemories, ListModelServers, ListOpenCodeProviders, ListPluginRuntimeContributions,
|
||||
ListPlugins, ListProfiles, ListProjectFiles, ListProjectPluginSettings, ListProjects,
|
||||
ListResumableAgents, ListSkills, ListSlashCommands, ListSprints, ListTemplates,
|
||||
LiveAgentRegistry, LiveSessions, LiveStateLeanProvider, LiveStateProvider,
|
||||
LiveStateReadProvider, LoadLayout, MarkIssueAttachmentSummarized, McpRuntime,
|
||||
McpToolPermissionCatalogue, MoveTabToNewWindow, MutateAgentPluginSkill, MutateAgentPluginTool,
|
||||
MutateLayout, OnnxModelView, OpenPluginLayoutWindow, OpenProject, OpenTerminal,
|
||||
OpenTicketAssistant, OrchestratorService, PairAttemptLimiter, PairDevice,
|
||||
PermissionProjectorRegistry, PluginCommandTasks, PluginConfigDocuments,
|
||||
PluginEventSubscriptions, PluginStorageAccess, PluginToolchainDiagnostics,
|
||||
PluginWorkspaceAccess, PluginWorkspaceExecTool, ProjectPluginResolver, ProposeContext,
|
||||
PurgeManagedTemp, QueryProjectStructure, ReadAgentContext, ReadChatDraft, ReadContext,
|
||||
ReadConversationPage, ReadCustomProjectIconAsset, ReadIssue, ReadIssueAttachment,
|
||||
ReadIssueCarnet, ReadMcpToolPermissions, ReadMemory, ReadMemoryIndex,
|
||||
ReadOpenProjectRestoreState, ReadProjectContext, ReadProjectSettings, ReadSkill, ReadTemplate,
|
||||
ReadUserSettings, RecallMemory, ReconcileLayouts, ReconcileLiveState, ReconcileLiveStateInput,
|
||||
ReconcilePluginMcpServers, RecordProjectClosedForRestore, RecordProjectOpenedForRestore,
|
||||
@ -74,16 +77,16 @@ use domain::events::AgentRestartPhase;
|
||||
use domain::ports::{
|
||||
AgentContextStore, AgentRuntime, AgentSession, AgentSessionFactory, AgentToolPolicyStore,
|
||||
AgentWakePort, AssistantContextProvider, BackgroundTaskPortError, BackgroundTaskRunner,
|
||||
BackgroundTaskStore, ChatAttachmentStore, ChatDraftStore, Clock, DeviceSessionStore, Embedder,
|
||||
EmbedderEnvInspector, EmbedderProfileStore, EmbedderPromptStore, EnvironmentReader, EventBus,
|
||||
FileSystem, GitPort, IdGenerator, IssueNumberAllocator, IssueStore, ManagedTempStore,
|
||||
McpToolPermissionStore, MemoryRecall, MemoryStore, ModelArtifactDownloader,
|
||||
OpenProjectRestoreStore, PermissionStore, PluginManifestValidator, PluginMcpSupervisor,
|
||||
PluginPackageStore, PluginRegistryStore, PluginStorageStore, ProcessSpawner, ProfileStore,
|
||||
ProjectPluginSettingsStore, ProjectSettingsStore, ProjectStore, PtyHandle, PtyPort,
|
||||
RuntimePermissionProbe, ScheduledTask, Scheduler, SecretStore, SkillStore, SprintStore,
|
||||
StructuredSessionEnvironmentPreparer, SystemPermissionStore, TemplateStore, ToolInvoker,
|
||||
UserSettingsStore, WakeError, WakeReason, WindowStateStore,
|
||||
BackgroundTaskStore, ChatAttachmentStore, ChatDraftStore, Clock, CustomProjectIconAssetStore,
|
||||
DeviceSessionStore, Embedder, EmbedderEnvInspector, EmbedderProfileStore, EmbedderPromptStore,
|
||||
EnvironmentReader, EventBus, FileSystem, GitPort, IdGenerator, IssueNumberAllocator,
|
||||
IssueStore, ManagedTempStore, McpToolPermissionStore, MemoryRecall, MemoryStore,
|
||||
ModelArtifactDownloader, OpenProjectRestoreStore, PermissionStore, PluginManifestValidator,
|
||||
PluginMcpSupervisor, PluginPackageStore, PluginRegistryStore, PluginStorageStore,
|
||||
ProcessSpawner, ProfileStore, ProjectPluginSettingsStore, ProjectSettingsStore, ProjectStore,
|
||||
PtyHandle, PtyPort, RuntimePermissionProbe, ScheduledTask, Scheduler, SecretStore, SkillStore,
|
||||
SprintStore, StructuredSessionEnvironmentPreparer, SystemPermissionStore, TemplateStore,
|
||||
ToolInvoker, UserSettingsStore, WakeError, WakeReason, WindowStateStore,
|
||||
};
|
||||
use domain::profile::{
|
||||
AgentProfile, ContextInjection, McpConfigStrategy, McpTransport, StructuredAdapter,
|
||||
@ -104,22 +107,22 @@ use infrastructure::{
|
||||
CliAgentRuntime, CodexPermissionProjector, CommandBackgroundRunner,
|
||||
DiagnosticPluginWorkspaceExecAudit, EmbeddedCompatibilityMatrix, EmbedderEnvProbe,
|
||||
ExternalMcpPluginSupervisor, FsAssistantContextStore, FsBackgroundTaskStore,
|
||||
FsChatAttachmentStore, FsChatDraftStore, FsConversationLog, FsDeviceSessionStore,
|
||||
FsEmbedderProfileStore, FsEmbedderPromptStore, FsHandoffStore, FsIssueNumberAllocator,
|
||||
FsIssueStore, FsLiveStateStore, FsManagedTempStore, FsMcpToolPermissionStore, FsMemoryStore,
|
||||
FsModelServerRegistry, FsOpenProjectRestoreStore, FsOrchestratorWatcher, FsPermissionStore,
|
||||
FsPluginPackageStore, FsPluginRegistryStore, FsPluginStorageStore, FsProfileStore,
|
||||
FsProjectPluginSettingsStore, FsProjectSettingsStore, FsProjectStore, FsProviderSessionStore,
|
||||
FsScheduledProjectTaskStore, FsSecretStore, FsSkillStore, FsSprintStore,
|
||||
FsSystemPermissionStore, FsTemplateStore, FsUserSettingsStore, FsWindowStateStore,
|
||||
FsWorkspaceToolProvider, Git2Repository, HeuristicHandoffSummarizer, HfModelArtifactDownloader,
|
||||
HttpOpenAiCompatibleProbe, HttpProviderModelCatalogue, IdeaiContextStore,
|
||||
InMemoryConversationRegistry, InMemoryMailbox, InMemoryPairAttemptLimiter, LlamaCppRuntime,
|
||||
LocalEnvironmentReader, LocalFileSystem, LocalManagedProcess, LocalProcessSpawner,
|
||||
LocalWorkspaceToolRunner, ManagedTempToolProvider, McpServer, MediatedInbox, NaiveMemoryRecall,
|
||||
OrchestratorWatchHandle, PortablePtyAdapter, ProcessCliVersionReader,
|
||||
ReadOnlyRuntimePermissionProbe, RwFileGuard, StructuredSessionFactory, SystemClock,
|
||||
SystemMillisClock, TemplateToolProvider, TicketAssistantEnvironmentPreparer,
|
||||
FsChatAttachmentStore, FsChatDraftStore, FsConversationLog, FsCustomProjectIconAssetStore,
|
||||
FsDeviceSessionStore, FsEmbedderProfileStore, FsEmbedderPromptStore, FsHandoffStore,
|
||||
FsIssueNumberAllocator, FsIssueStore, FsLiveStateStore, FsManagedTempStore,
|
||||
FsMcpToolPermissionStore, FsMemoryStore, FsModelServerRegistry, FsOpenProjectRestoreStore,
|
||||
FsOrchestratorWatcher, FsPermissionStore, FsPluginPackageStore, FsPluginRegistryStore,
|
||||
FsPluginStorageStore, FsProfileStore, FsProjectPluginSettingsStore, FsProjectSettingsStore,
|
||||
FsProjectStore, FsProviderSessionStore, FsScheduledProjectTaskStore, FsSecretStore,
|
||||
FsSkillStore, FsSprintStore, FsSystemPermissionStore, FsTemplateStore, FsUserSettingsStore,
|
||||
FsWindowStateStore, FsWorkspaceToolProvider, Git2Repository, HeuristicHandoffSummarizer,
|
||||
HfModelArtifactDownloader, HttpOpenAiCompatibleProbe, HttpProviderModelCatalogue,
|
||||
IdeaiContextStore, InMemoryConversationRegistry, InMemoryMailbox, InMemoryPairAttemptLimiter,
|
||||
LlamaCppRuntime, LocalEnvironmentReader, LocalFileSystem, LocalManagedProcess,
|
||||
LocalProcessSpawner, LocalWorkspaceToolRunner, ManagedTempToolProvider, McpServer,
|
||||
MediatedInbox, NaiveMemoryRecall, OrchestratorWatchHandle, PortablePtyAdapter,
|
||||
ProcessCliVersionReader, ReadOnlyRuntimePermissionProbe, RwFileGuard, StructuredSessionFactory,
|
||||
SystemClock, SystemMillisClock, TemplateToolProvider, TicketAssistantEnvironmentPreparer,
|
||||
TicketToolProvider, TokioBroadcastEventBus, TokioScheduler, ToolPolicyRegistry, UuidGenerator,
|
||||
VectorMemoryRecall, WorkspaceToolProvider, DEFAULT_OLLAMA_BASE_URL, ONNX_CACHE_SUBDIR,
|
||||
RECOMMENDED_ONNX_MODELS, VECTOR_HTTP_ENABLED, VECTOR_ONNX_ENABLED,
|
||||
@ -2267,6 +2270,16 @@ pub struct BackendCore {
|
||||
pub read_project_settings: Arc<ReadProjectSettings>,
|
||||
/// Updates settings owned by the active project.
|
||||
pub update_project_settings: Arc<UpdateProjectSettings>,
|
||||
/// Imports into the shared custom icon library.
|
||||
pub import_custom_project_icon_asset: Arc<ImportCustomProjectIconAsset>,
|
||||
/// Lists shared custom icons with live usage.
|
||||
pub list_custom_project_icon_assets: Arc<ListCustomProjectIconAssets>,
|
||||
/// Reads one custom icon and exact bytes.
|
||||
pub read_custom_project_icon_asset: Arc<ReadCustomProjectIconAsset>,
|
||||
/// Gets current project usage for one custom icon.
|
||||
pub get_custom_project_icon_asset_usage: Arc<GetCustomProjectIconAssetUsage>,
|
||||
/// Deletes an unused custom icon.
|
||||
pub delete_custom_project_icon_asset: Arc<DeleteCustomProjectIconAsset>,
|
||||
/// Read the project permission document.
|
||||
pub get_project_permissions: Arc<GetProjectPermissions>,
|
||||
/// Update project-level default permissions.
|
||||
@ -2635,6 +2648,10 @@ impl BackendCore {
|
||||
let project_settings_store = Arc::new(FsProjectSettingsStore::new(Arc::clone(&fs_port)));
|
||||
let project_settings_store_port =
|
||||
Arc::clone(&project_settings_store) as Arc<dyn ProjectSettingsStore>;
|
||||
let custom_project_icon_asset_store =
|
||||
Arc::new(FsCustomProjectIconAssetStore::new(&app_data_dir));
|
||||
let custom_project_icon_asset_store_port =
|
||||
Arc::clone(&custom_project_icon_asset_store) as Arc<dyn CustomProjectIconAssetStore>;
|
||||
let read_user_settings =
|
||||
Arc::new(ReadUserSettings::new(Arc::clone(&user_settings_store_port)));
|
||||
let update_user_settings = Arc::new(UpdateUserSettings::new(Arc::clone(
|
||||
@ -2643,9 +2660,35 @@ impl BackendCore {
|
||||
let read_project_settings = Arc::new(ReadProjectSettings::new(Arc::clone(
|
||||
&project_settings_store_port,
|
||||
)));
|
||||
let update_project_settings = Arc::new(UpdateProjectSettings::new(Arc::clone(
|
||||
&project_settings_store_port,
|
||||
)));
|
||||
let update_project_settings = Arc::new(UpdateProjectSettings::new(
|
||||
Arc::clone(&project_settings_store_port),
|
||||
Arc::clone(&custom_project_icon_asset_store_port),
|
||||
));
|
||||
let import_custom_project_icon_asset = Arc::new(ImportCustomProjectIconAsset::new(
|
||||
Arc::clone(&custom_project_icon_asset_store_port),
|
||||
Arc::clone(&ids) as Arc<dyn IdGenerator>,
|
||||
Arc::clone(&clock) as Arc<dyn Clock>,
|
||||
));
|
||||
let list_custom_project_icon_assets = Arc::new(ListCustomProjectIconAssets::new(
|
||||
Arc::clone(&custom_project_icon_asset_store_port),
|
||||
Arc::clone(&store_port),
|
||||
Arc::clone(&project_settings_store_port),
|
||||
));
|
||||
let read_custom_project_icon_asset = Arc::new(ReadCustomProjectIconAsset::new(
|
||||
Arc::clone(&custom_project_icon_asset_store_port),
|
||||
Arc::clone(&store_port),
|
||||
Arc::clone(&project_settings_store_port),
|
||||
));
|
||||
let get_custom_project_icon_asset_usage = Arc::new(GetCustomProjectIconAssetUsage::new(
|
||||
Arc::clone(&custom_project_icon_asset_store_port),
|
||||
Arc::clone(&store_port),
|
||||
Arc::clone(&project_settings_store_port),
|
||||
));
|
||||
let delete_custom_project_icon_asset = Arc::new(DeleteCustomProjectIconAsset::new(
|
||||
custom_project_icon_asset_store_port,
|
||||
Arc::clone(&store_port),
|
||||
Arc::clone(&project_settings_store_port),
|
||||
));
|
||||
let open_project_restore_store_port =
|
||||
Arc::clone(&open_project_restore_store) as Arc<dyn OpenProjectRestoreStore>;
|
||||
let window_state_port = Arc::clone(&window_state_store) as Arc<dyn WindowStateStore>;
|
||||
@ -4514,6 +4557,11 @@ impl BackendCore {
|
||||
update_user_settings,
|
||||
read_project_settings,
|
||||
update_project_settings,
|
||||
import_custom_project_icon_asset,
|
||||
list_custom_project_icon_assets,
|
||||
read_custom_project_icon_asset,
|
||||
get_custom_project_icon_asset_usage,
|
||||
delete_custom_project_icon_asset,
|
||||
get_project_permissions,
|
||||
update_project_permissions,
|
||||
update_agent_permissions,
|
||||
|
||||
Reference in New Issue
Block a user