From 6d9a29d4ce3ef4e2b49f89e27ebafa07ae6da895 Mon Sep 17 00:00:00 2001 From: Mitch Francese <2227948+tux234@users.noreply.github.com> Date: Tue, 6 Jan 2026 22:59:11 -0500 Subject: [PATCH] Add NextCloud as a macOS Fleet-maintained app (#37903) - Add input manifest for nextcloud - Generate output files - Add description to apps.json --- .../inputs/homebrew/nextcloud.json | 8 +++++++ ee/maintained-apps/outputs/apps.json | 7 ++++++ .../outputs/nextcloud/darwin.json | 21 ++++++++++++++++++ .../components/icons/Nextcloud.tsx | 14 ++++++++++++ .../SoftwarePage/components/icons/index.ts | 2 ++ .../images/app-icon-nextcloud-60x60@2x.png | Bin 0 -> 8477 bytes 6 files changed, 52 insertions(+) create mode 100644 ee/maintained-apps/inputs/homebrew/nextcloud.json create mode 100644 ee/maintained-apps/outputs/nextcloud/darwin.json create mode 100644 frontend/pages/SoftwarePage/components/icons/Nextcloud.tsx create mode 100644 website/assets/images/app-icon-nextcloud-60x60@2x.png diff --git a/ee/maintained-apps/inputs/homebrew/nextcloud.json b/ee/maintained-apps/inputs/homebrew/nextcloud.json new file mode 100644 index 0000000000..925a79138f --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/nextcloud.json @@ -0,0 +1,8 @@ +{ + "name": "Nextcloud", + "slug": "nextcloud/darwin", + "unique_identifier": "com.nextcloud.desktopclient", + "token": "nextcloud", + "installer_format": "pkg", + "default_categories": ["Productivity"] +} diff --git a/ee/maintained-apps/outputs/apps.json b/ee/maintained-apps/outputs/apps.json index 84068beff7..e94f6ed484 100644 --- a/ee/maintained-apps/outputs/apps.json +++ b/ee/maintained-apps/outputs/apps.json @@ -1037,6 +1037,13 @@ "unique_identifier": "com.oracle.workbench.MySQLWorkbench", "description": "MySQL Workbench is a visual tool to design, develop and administer MySQL servers." }, + { + "name": "Nextcloud", + "slug": "nextcloud/darwin", + "platform": "darwin", + "unique_identifier": "com.nextcloud.desktopclient", + "description": "Nextcloud is a self-hosted file sync and sharing platform that provides secure access to your data across devices with collaboration features." + }, { "name": "NordPass", "slug": "nordpass/darwin", diff --git a/ee/maintained-apps/outputs/nextcloud/darwin.json b/ee/maintained-apps/outputs/nextcloud/darwin.json new file mode 100644 index 0000000000..d5dbd84f27 --- /dev/null +++ b/ee/maintained-apps/outputs/nextcloud/darwin.json @@ -0,0 +1,21 @@ +{ + "versions": [ + { + "version": "4.0.4", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.nextcloud.desktopclient';" + }, + "installer_url": "https://github.com/nextcloud-releases/desktop/releases/download/v4.0.4/Nextcloud-4.0.4.pkg", + "install_script_ref": "08ac92bf", + "uninstall_script_ref": "3b1b8e75", + "sha256": "0540be72d12e40c1f85a446c1b2fccf08758b79a189bf1b9bc99ea42d5c2f82f", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "08ac92bf": "#!/bin/sh\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath $INSTALLER_PATH)\")\n\n# install pkg files\nsudo installer -pkg \"$TMPDIR/Nextcloud-4.0.4.pkg\" -target /\n", + "3b1b8e75": "#!/bin/sh\n\n# variables\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nexpand_pkgid_and_map() {\n local PKGID=\"$1\"\n local FUNC=\"$2\"\n if [[ \"$PKGID\" == *\"*\" ]]; then\n local prefix=\"${PKGID%\\*}\"\n echo \"Expanding wildcard for PKGID: $PKGID\"\n for receipt in $(pkgutil --pkgs | grep \"^${prefix}\"); do\n echo \"Processing $receipt\"\n \"$FUNC\" \"$receipt\"\n done\n else\n \"$FUNC\" \"$PKGID\"\n fi\n}\n\nforget_pkg() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" forget_receipt\n}\n\nforget_receipt() {\n local PKGID=\"$1\"\n sudo pkgutil --forget \"$PKGID\"\n}\n\nquit_application() {\n local bundle_id=\"$1\"\n local timeout_duration=10\n\n # check if the application is running\n if ! osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ $EUID -eq 0 && \"$console_user\" == \"root\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nremove_launchctl_service() {\n local service=\"$1\"\n local booleans=(\"true\" \"false\")\n local plist_status\n local paths\n local should_sudo\n\n echo \"Removing launchctl service ${service}\"\n\n for should_sudo in \"${booleans[@]}\"; do\n plist_status=$(launchctl list \"${service}\" 2>/dev/null)\n\n if [[ $plist_status == \\{* ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo launchctl remove \"${service}\"\n else\n launchctl remove \"${service}\"\n fi\n sleep 1\n fi\n\n paths=(\n \"/Library/LaunchAgents/${service}.plist\"\n \"/Library/LaunchDaemons/${service}.plist\"\n )\n\n # if not using sudo, prepend the home directory to the paths\n if [[ $should_sudo == \"false\" ]]; then\n for i in \"${!paths[@]}\"; do\n paths[i]=\"${HOME}${paths[i]}\"\n done\n fi\n\n for path in \"${paths[@]}\"; do\n if [[ -e \"$path\" ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo rm -f -- \"$path\"\n else\n rm -f -- \"$path\"\n fi\n fi\n done\n done\n}\n\nremove_pkg_files() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" remove_receipt_files\n}\n\nremove_receipt_files() {\n local PKGID=\"$1\"\n local PKGINFO VOLUME INSTALL_LOCATION FULL_INSTALL_LOCATION\n\n echo \"pkgutil --pkg-info-plist \\\"$PKGID\\\"\"\n PKGINFO=$(pkgutil --pkg-info-plist \"$PKGID\")\n VOLUME=$(echo \"$PKGINFO\" | awk '/volume<\\/key>/ {getline; gsub(/.*|<\\/string>.*/, \"\"); print}')\n INSTALL_LOCATION=$(echo \"$PKGINFO\" | awk '/install-location<\\/key>/ {getline; gsub(/.*|<\\/string>.*/, \"\"); print}')\n\n if [ -z \"$INSTALL_LOCATION\" ] || [ \"$INSTALL_LOCATION\" = \"/\" ]; then\n FULL_INSTALL_LOCATION=\"$VOLUME\"\n else\n FULL_INSTALL_LOCATION=\"$VOLUME/$INSTALL_LOCATION\"\n FULL_INSTALL_LOCATION=$(echo \"$FULL_INSTALL_LOCATION\" | sed 's|//|/|g')\n fi\n\n echo \"sudo pkgutil --only-files --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-files --files \"$PKGID\" | sed \"s|^|/${INSTALL_LOCATION}/|\" | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n echo \"sudo pkgutil --only-dirs --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | grep '\\\\.app$' | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-dirs --files \"$PKGID\" | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" | grep '\\.app$' | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n root_app_dir=$(\n sudo pkgutil --only-dirs --files \"$PKGID\" \\\n | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" \\\n | grep 'Applications' \\\n | awk '{ print length, $0 }' \\\n | sort -n \\\n | head -n1 \\\n | cut -d' ' -f2-\n )\n if [ -n \"$root_app_dir\" ]; then\n echo \"sudo rmdir -p \\\"$root_app_dir\\\" 2>/dev/null || :\"\n sudo rmdir -p \"$root_app_dir\" 2>/dev/null || :\n fi\n}\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nremove_launchctl_service 'com.nextcloud.desktopclient'\nquit_application 'com.nextcloud.desktopclient'\nremove_pkg_files 'com.nextcloud.desktopclient'\nforget_pkg 'com.nextcloud.desktopclient'\nsudo rm -rf '/Applications/Nextcloud.app'\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/com.nextcloud.desktopclient.FinderSyncExt'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Nextcloud'\ntrash $LOGGED_IN_USER '~/Library/Caches/Nextcloud'\ntrash $LOGGED_IN_USER '~/Library/Containers/com.nextcloud.desktopclient.FinderSyncExt'\ntrash $LOGGED_IN_USER '~/Library/Group Containers/com.nextcloud.desktopclient'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.nextcloud.desktopclient.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/Nextcloud'\n" + } +} diff --git a/frontend/pages/SoftwarePage/components/icons/Nextcloud.tsx b/frontend/pages/SoftwarePage/components/icons/Nextcloud.tsx new file mode 100644 index 0000000000..5b87d03bd1 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Nextcloud.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Nextcloud = (props: SVGProps) => ( + + + +); +export default Nextcloud; diff --git a/frontend/pages/SoftwarePage/components/icons/index.ts b/frontend/pages/SoftwarePage/components/icons/index.ts index 8ef005ef44..d19bc5a819 100644 --- a/frontend/pages/SoftwarePage/components/icons/index.ts +++ b/frontend/pages/SoftwarePage/components/icons/index.ts @@ -5,6 +5,7 @@ import { HOST_LINUX_PLATFORMS } from "interfaces/platform"; import { ISoftware } from "interfaces/software"; import CrashPlan from "./CrashPlan"; +import Nextcloud from "./Nextcloud"; import Notepad from "./Notepad++"; import OktaVerify from "./OktaVerify"; import SevenZip from "./7Zip"; @@ -370,6 +371,7 @@ export const SOFTWARE_NAME_TO_ICON_MAP = { "microsoft word": Word, miro: Miro, "mysql workbench": MySqlWorkbench, + nextcloud: Nextcloud, "nord vpn": NordVpn, nordpass: Nordpass, nordvpn: NordVpn, diff --git a/website/assets/images/app-icon-nextcloud-60x60@2x.png b/website/assets/images/app-icon-nextcloud-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..f5978a1c214db1ad5b63ee4d056684a2a55cae72 GIT binary patch literal 8477 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