Skip to content

[stable-33.0] Server Actions Integration for File Provider Extension#9486

Merged
i2h3 merged 2 commits intostable-33.0from
backport/9469/stable-33.0
Feb 24, 2026
Merged

[stable-33.0] Server Actions Integration for File Provider Extension#9486
i2h3 merged 2 commits intostable-33.0from
backport/9469/stable-33.0

Conversation

@backportbot
Copy link

@backportbot backportbot bot commented Feb 23, 2026

Backport of #9469

Warning, This backport's changes differ from the original and might be incomplete ⚠️

Todo

  • Review and resolve any conflicts
  • Amend HEAD commit to remove the line stating to skip CI

Learn more about backports at https://docs.nextcloud.com/server/stable/go.php?to=developer-backports.

@backportbot backportbot bot requested a review from i2h3 February 23, 2026 11:51
@backportbot backportbot bot added os: 🍎 macOS Apple macOS, formerly also known as OS X feature: ☁️ GUI System tray icon and menu. feature: 🐚 shell integration 3. to review feature: 📁 file provider macOS File Provider Extension, more general also known as virtual file system. labels Feb 23, 2026
@backportbot backportbot bot added this to the 33.0.0 milestone Feb 23, 2026
…ension

- Introduced a new presentFileActions: method in the XPC interface of the main app.
- Implemented the presentFileActions: method in the main app to call existing code for file action presentation.
- Added the new custom action to the build-time declarations of custom actions in the Info.plist of the file provider extension.
- Extended the custom actions handling code switch to process the invocation and call the main app via XPC.

Chores:
- Created a shared file provider manager object and related stored property for the lifetime of the file provider extension object to be used in various places in its implementation. In example: resolving the user-visible URL of the item to present file actions for.

Signed-off-by: Iva Horn <iva.horn@nextcloud.com>
@i2h3 i2h3 force-pushed the backport/9469/stable-33.0 branch from ce3a6f2 to 0011247 Compare February 23, 2026 15:56
Signed-off-by: Iva Horn <iva.horn@nextcloud.com>
@i2h3 i2h3 force-pushed the backport/9469/stable-33.0 branch from 0011247 to 489eda6 Compare February 23, 2026 15:57
@i2h3 i2h3 marked this pull request as ready for review February 23, 2026 16:00
Copilot AI review requested due to automatic review settings February 23, 2026 16:00
@github-actions
Copy link

Artifact containing the AppImage: nextcloud-appimage-pr-9486.zip

Digest: sha256:c9834d5df0a7f65706f818baf4dcf53e81b3d0597c98e0449c51f962bd104da3

To test this change/fix you can download the above artifact file, unzip it, and run it.

Please make sure to quit your existing Nextcloud app and backup your data.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request is a backport of #9469 to the stable-33.0 branch, implementing server actions integration for the macOS file provider extension. The implementation enables context menu items defined by the server to be displayed and executed for files managed by the file provider extension, extending file actions support beyond traditional synchronized folders to virtual file systems.

Changes:

  • Added XPC communication support for displaying file actions dialogs from the file provider extension
  • Extended FileActionsModel to support both synchronized folders and file provider-managed files via optional fileId and remoteItemPath parameters
  • Integrated server-defined context menu item filtering based on MIME types using NextcloudCapabilitiesKit 2.5.0
  • Modernized macOS extension logging from NSLog to os_log framework

Reviewed changes

Copilot reviewed 31 out of 31 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/gui/systray.h Added method declarations for file provider file actions dialog support
src/gui/systray.cpp Implemented file provider file actions dialog creation and account state resolution
src/gui/owncloudgui.cpp Connected file provider service signal to systray slot for showing file actions
src/gui/integration/fileactionsmodel.h Added fileId and remoteItemPath properties to support file provider scenarios
src/gui/integration/fileactionsmodel.cpp Implemented property setters and updated logic to handle both sync folders and file providers
src/gui/integration/FileActionsWindow.qml Added fileId and remoteItemPath properties to QML component
src/gui/macOS/fileproviderservice.h Declared new signal for showing file actions dialog
src/gui/macOS/fileproviderservice.mm Implemented XPC callback for presentFileActions with thread-safe signal emission
shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/Info.plist Added NCApplicationGroupIdentifier configuration
shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/FinderSync.m Replaced NSLog with os_log and updated to use NCApplicationGroupIdentifier
shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/FinderSyncSocketLineProcessor.m Migrated logging to os_log framework
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/AppProtocol.h Added presentFileActions XPC protocol method
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Info.plist Added File Actions custom action configuration
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension.swift Added manager property and refactored to use it consistently
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension+CustomActions.swift Implemented FileActionsAction handler to present file actions
shell_integration/MacOSX/NextcloudFileProviderKit/Sources/NextcloudFileProviderKit/Item/Item.swift Added displayFileActions property and included it in userInfo
shell_integration/MacOSX/NextcloudFileProviderKit/Sources/NextcloudFileProviderKit/Item/Item+*.swift Updated Item initialization calls to include displayFileActions parameter
shell_integration/MacOSX/NextcloudFileProviderKit/Sources/NextcloudFileProviderKit/Item/Item+typeHasApplicableContextMenuItems.swift Added methods to check MIME type against context menu filters
shell_integration/MacOSX/NextcloudFileProviderKit/Sources/NextcloudFileProviderKit/Item/Item+getContextMenuItemTypeFilters.swift Added method to fetch MIME type filters from server capabilities
shell_integration/MacOSX/NextcloudFileProviderKit/Sources/NextcloudFileProviderKit/Metadata/SendableItemMetadata+Array.swift Optimized to fetch filters once and reuse for all items
shell_integration/MacOSX/NextcloudFileProviderKit/Tests/**/*.swift Updated test code to include displayFileActions parameter
shell_integration/MacOSX/NextcloudFileProviderKit/Package.swift Updated NextcloudCapabilitiesKit dependency to 2.5.0
shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved Updated resolved package version to 2.5.0

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +125 to +130
_fileId = fileId;

if (_accountState && !_localPath.isEmpty()) {
parseEndpoints();
}

Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When creating a file actions dialog for a synchronized folder, the fileId parameter defaults to an empty string. This empty string will overwrite the correct _fileId that was retrieved from the sync journal database in setupFileProperties() (line 168). This happens because the QML property binding sets fileId: root.fileId after localPath has already been set, and the empty fileId value overwrites the database-retrieved value.

To fix this, setFileId should check if the incoming fileId is empty and avoid overwriting _fileId when it's already been set from the database. Alternatively, the property initialization order in QML could be changed, or setFileId could be made smarter about when to update.

Suggested change
_fileId = fileId;
if (_accountState && !_localPath.isEmpty()) {
parseEndpoints();
}
// Avoid overwriting a valid fileId (e.g. loaded from the sync journal)
// with an empty one coming from default QML property initialization.
if (fileId.isEmpty() && !_fileId.isEmpty()) {
return;
}
_fileId = fileId;
if (_accountState && !_localPath.isEmpty()) {
parseEndpoints();
}

Copilot uses AI. Check for mistakes.
Comment on lines +33 to +56
- (void)presentFileActions:(NSString *)fileId path:(NSString *)path remoteItemPath:(NSString *)remoteItemPath withDomainIdentifier:(NSString *)domainIdentifier
{
qCDebug(OCC::lcMacFileProviderService) << "Should present file actions for item with fileId:"
<< fileId
<< "and path:"
<< path
<< "remote item path:"
<< remoteItemPath
<< "domain identifier:"
<< domainIdentifier;

const auto qFileId = QString::fromNSString(fileId);
const auto localPath = QString::fromNSString(path);
const auto qRemoteItemPath = QString::fromNSString(remoteItemPath);
const auto domainId = QString::fromNSString(domainIdentifier);

// Use QMetaObject::invokeMethod to emit the signal on the correct thread
// since this callback may be called on an XPC dispatch queue (non-main thread)
QMetaObject::invokeMethod(_service, "showFileActionsDialog", Qt::QueuedConnection,
Q_ARG(QString, qFileId),
Q_ARG(QString, localPath),
Q_ARG(QString, qRemoteItemPath),
Q_ARG(QString, domainId));
}
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The presentFileActions method accesses _service pointer without checking if it's null (line 51). In contrast, the reportSyncStatus method includes a null check for _service before using it (lines 67-69). If the FileProviderService is destroyed while an XPC callback is pending, this could lead to accessing a dangling pointer. Consider adding a null check similar to reportSyncStatus before calling QMetaObject::invokeMethod.

Copilot uses AI. Check for mistakes.
Comment on lines +184 to +188
/**
* @param fileId This is optional and null by default. Only when there are no synchronization folders configured (for example when only a file provider is used) is this value required.
* @param remoteItemPath The server-side path of the item. Used as a fallback to determine the success response URL when no sync folder is configured.
*/
void createFileActionsDialogWithAccountState(const QString &localPath, AccountState *accountState, const QString &fileId = {}, const QString &remoteItemPath = {});
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation comment says "This is optional and null by default" but QString in C++ doesn't have a null state in the traditional sense - it can be empty but is always a valid object. Consider updating the comment to say "This is optional and empty by default" to be more precise about QString's behavior.

Copilot uses AI. Check for mistakes.
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
0.0% Coverage on New Code (required ≥ 80%)
5 New Code Smells (required ≤ 0)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@i2h3 i2h3 merged commit 8f6f33c into stable-33.0 Feb 24, 2026
24 of 27 checks passed
@i2h3 i2h3 deleted the backport/9469/stable-33.0 branch February 24, 2026 08:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

3. to review feature: ☁️ GUI System tray icon and menu. feature: 📁 file provider macOS File Provider Extension, more general also known as virtual file system. feature: 🐚 shell integration os: 🍎 macOS Apple macOS, formerly also known as OS X

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant