diff --git a/README.md b/README.md index 818a875..7ae3543 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,8 @@ See [API reference](https://activitysmith.com/docs/api-reference/introduction). - [Start & Update Live Activity](#start--update-live-activity) - [End Live Activity](#end-live-activity) - [Live Activity Action](#live-activity-action) + - [Icons and Badges](#icons-and-badges) + - [Live Activity Colors](#live-activity-colors) - [Channels](#channels) - [Widgets](#widgets) @@ -264,14 +266,6 @@ activitysmith.live_activities.stream( ) ``` -The `icon` symbol value is an Apple SF Symbol name. Browse the catalog with one of these tools: - -- [ActivitySmith app](https://apps.apple.com/us/app/activitysmith/id6752254835) - Open Settings -> SF Symbols to browse 45 hand-picked icons ready to use -- [SF Symbols](https://developer.apple.com/sf-symbols/) - Apple's official macOS app -- [Interactful](https://apps.apple.com/app/interactful/id1528095640) - free third-party iOS app listing all SF Symbols under Foundations -> Iconography - -`icon` and `badge` are optional. If you omit either one, that element is not shown in the Live Activity. - ### End Live Activity Call `end_stream(...)` with the same `stream_key` to dismiss the Live Activity. You can include final values before it is removed. By default, iOS removes the Live Activity after two minutes. Set `auto_dismiss_minutes` to choose a different dismissal time, including `0` for immediate dismissal. @@ -358,6 +352,79 @@ activitysmith.live_activities.stream( ) ``` +### Icons and Badges + +Add more context to Live Activities with icons and badges. + +#### Icon + +Supported Live Activity types: `stats`, `metrics`, `progress`, `segmented_progress`, and `alert`. + +

+ Metrics Live Activity with an SF Symbol icon on the iPhone Lock Screen +

+ +```ruby +activitysmith.live_activities.stream( + "prod-web-1", + { + content_state: ActivitySmith::LiveActivities.content_state( + title: "Server Health", + subtitle: "prod-web-1", + type: "metrics", + icon: ActivitySmith::LiveActivities.alert_icon("server.rack", color: "blue"), + metrics: [ + { label: "CPU", value: 18, unit: "%" }, + { label: "MEM", value: 42, unit: "%" } + ] + ) + } +) +``` + +The `icon` symbol value is an Apple SF Symbol name. Browse the catalog with one of these tools: + +- [ActivitySmith app](https://apps.apple.com/us/app/activitysmith/id6752254835) - Open Settings -> SF Symbols to browse 45 hand-picked icons ready to use +- [SF Symbols](https://developer.apple.com/sf-symbols/) - Apple's official macOS app +- [Interactful](https://apps.apple.com/app/interactful/id1528095640) - free third-party iOS app listing all SF Symbols under Foundations -> Iconography + +#### Badge + +Badges are supported by `alert`, `progress`, and `segmented_progress` Live Activities. + +

+ Progress Live Activity with a badge on the iPhone Lock Screen +

+ +```ruby +activitysmith.live_activities.stream( + "nightly-database-backup", + { + content_state: ActivitySmith::LiveActivities.content_state( + title: "Nightly Database Backup", + subtitle: "verify restore", + type: "progress", + badge: ActivitySmith::LiveActivities.alert_badge("S3", color: "cyan"), + percentage: 62 + ) + } +) +``` + +### Live Activity Colors + +Choose from these colors for the Live Activity accent, including progress bars and action buttons, or apply them to an individual icon or badge: + +`lime`, `green`, `cyan`, `blue`, `purple`, `magenta`, `red`, `orange`, `yellow`, `gray` + ## Channels Channels are used to target specific team members or devices. Can be used for both push notifications and live activities. diff --git a/generated/activitysmith_openapi/models/content_state_end.rb b/generated/activitysmith_openapi/models/content_state_end.rb index 150a269..1c263e2 100644 --- a/generated/activitysmith_openapi/models/content_state_end.rb +++ b/generated/activitysmith_openapi/models/content_state_end.rb @@ -14,7 +14,7 @@ require 'time' module OpenapiClient - # End payload requires title. For segmented_progress include current_step and optionally number_of_steps. For progress include percentage or value with upper_limit. For metrics and stats include a non-empty metrics array. For alert include message, with optional icon and badge. Type is optional when ending an existing activity. You can send an updated number_of_steps here if the workflow changed after start. + # End payload requires title. For segmented_progress include current_step and optionally number_of_steps. For progress include percentage or value with upper_limit. For metrics and stats include a non-empty metrics array. For alert include message. Optional icon is supported by all Live Activity types. Optional badge is supported by alert, progress, and segmented_progress. Type is optional when ending an existing activity. You can send an updated number_of_steps here if the workflow changed after start. class ContentStateEnd attr_accessor :title @@ -41,10 +41,10 @@ class ContentStateEnd # Alert message. Use for type=alert. attr_accessor :message - # Optional SF Symbol icon for type=alert. + # Optional SF Symbol icon. Supported by alert, progress, segmented_progress, metrics, and stats. attr_accessor :icon - # Optional badge for type=alert. + # Optional badge. Supported by alert, progress, and segmented_progress. attr_accessor :badge # Optional. When omitted, the API uses the existing Live Activity type. diff --git a/generated/activitysmith_openapi/models/content_state_start.rb b/generated/activitysmith_openapi/models/content_state_start.rb index 2b73e6b..ed23510 100644 --- a/generated/activitysmith_openapi/models/content_state_start.rb +++ b/generated/activitysmith_openapi/models/content_state_start.rb @@ -14,7 +14,7 @@ require 'time' module OpenapiClient - # Start payload requires title and type. For segmented_progress include number_of_steps and current_step. For progress include percentage or value with upper_limit. For metrics and stats include a non-empty metrics array. For alert include message, with optional icon and badge. For segmented_progress, number_of_steps is not locked and can be changed in later update or end calls. + # Start payload requires title and type. For segmented_progress include number_of_steps and current_step. For progress include percentage or value with upper_limit. For metrics and stats include a non-empty metrics array. For alert include message. Optional icon is supported by all Live Activity types. Optional badge is supported by alert, progress, and segmented_progress. For segmented_progress, number_of_steps is not locked and can be changed in later update or end calls. class ContentStateStart attr_accessor :title @@ -41,10 +41,10 @@ class ContentStateStart # Required for type=alert. attr_accessor :message - # Optional SF Symbol icon for type=alert. + # Optional SF Symbol icon. Supported by alert, progress, segmented_progress, metrics, and stats. attr_accessor :icon - # Optional badge for type=alert. + # Optional badge. Supported by alert, progress, and segmented_progress. attr_accessor :badge attr_accessor :type diff --git a/generated/activitysmith_openapi/models/content_state_update.rb b/generated/activitysmith_openapi/models/content_state_update.rb index 454a640..08760d9 100644 --- a/generated/activitysmith_openapi/models/content_state_update.rb +++ b/generated/activitysmith_openapi/models/content_state_update.rb @@ -14,7 +14,7 @@ require 'time' module OpenapiClient - # Update payload requires title. For segmented_progress include current_step and optionally number_of_steps. For progress include percentage or value with upper_limit. For metrics and stats include a non-empty metrics array. For alert include message, with optional icon and badge. Type is optional when updating an existing activity. You can increase or decrease number_of_steps during updates. + # Update payload requires title. For segmented_progress include current_step and optionally number_of_steps. For progress include percentage or value with upper_limit. For metrics and stats include a non-empty metrics array. For alert include message. Optional icon is supported by all Live Activity types. Optional badge is supported by alert, progress, and segmented_progress. Type is optional when updating an existing activity. You can increase or decrease number_of_steps during updates. class ContentStateUpdate attr_accessor :title @@ -41,10 +41,10 @@ class ContentStateUpdate # Alert message. Use for type=alert. attr_accessor :message - # Optional SF Symbol icon for type=alert. + # Optional SF Symbol icon. Supported by alert, progress, segmented_progress, metrics, and stats. attr_accessor :icon - # Optional badge for type=alert. + # Optional badge. Supported by alert, progress, and segmented_progress. attr_accessor :badge # Optional. When omitted, the API uses the existing Live Activity type. diff --git a/generated/activitysmith_openapi/models/live_activity_action.rb b/generated/activitysmith_openapi/models/live_activity_action.rb index d54fbb5..38fc7b9 100644 --- a/generated/activitysmith_openapi/models/live_activity_action.rb +++ b/generated/activitysmith_openapi/models/live_activity_action.rb @@ -21,7 +21,7 @@ class LiveActivityAction attr_accessor :type - # HTTPS URL. For open_url it is opened in browser. For webhook it is called by ActivitySmith backend. + # Action URL. For open_url, use an HTTPS or shortcuts:// URL. For webhook, use an HTTPS URL called by the ActivitySmith backend. attr_accessor :url # Webhook HTTP method. Used only when type=webhook. @@ -30,28 +30,6 @@ class LiveActivityAction # Optional webhook payload body. Used only when type=webhook. attr_accessor :body - class EnumAttributeValidator - attr_reader :datatype - attr_reader :allowable_values - - def initialize(datatype, allowable_values) - @allowable_values = allowable_values.map do |value| - case datatype.to_s - when /Integer/i - value.to_i - when /Float/i - value.to_f - else - value - end - end - end - - def valid?(value) - !value || allowable_values.include?(value) - end - end - # Attribute mapping from ruby-style variable name to JSON key. def self.attribute_map { @@ -117,6 +95,7 @@ def initialize(attributes = {}) else self.url = nil end + validate_action_url! if attributes.key?(:'method') self.method = attributes[:'method'] @@ -131,6 +110,16 @@ def initialize(attributes = {}) end end + def validate_action_url! + return if @url.nil? || @type.nil? + if @type == LiveActivityActionType::OPEN_URL && @url !~ /\A(https|shortcuts):\/\// + fail ArgumentError, 'invalid value for "url", open_url must use https or shortcuts.' + end + if @type == LiveActivityActionType::WEBHOOK && @url !~ /\Ahttps:\/\// + fail ArgumentError, 'invalid value for "url", webhook must use https.' + end + end + # Show invalid properties with the reasons. Usually used together with valid? # @return Array for valid properties with the reasons def list_invalid_properties @@ -147,10 +136,11 @@ def list_invalid_properties if @url.nil? invalid_properties.push('invalid value for "url", url cannot be nil.') end - - pattern = Regexp.new(/^https:\/\//) - if @url !~ pattern - invalid_properties.push("invalid value for \"url\", must conform to the pattern #{pattern}.") + if !@url.nil? && @type == LiveActivityActionType::OPEN_URL && @url !~ /\A(https|shortcuts):\/\// + invalid_properties.push('invalid value for "url", open_url must use https or shortcuts.') + end + if !@url.nil? && @type == LiveActivityActionType::WEBHOOK && @url !~ /\Ahttps:\/\// + invalid_properties.push('invalid value for "url", webhook must use https.') end invalid_properties @@ -163,25 +153,11 @@ def valid? return false if @title.nil? return false if @type.nil? return false if @url.nil? - return false if @url !~ Regexp.new(/^https:\/\//) + return false if !@url.nil? && @type == LiveActivityActionType::OPEN_URL && @url !~ /\A(https|shortcuts):\/\// + return false if !@url.nil? && @type == LiveActivityActionType::WEBHOOK && @url !~ /\Ahttps:\/\// true end - # Custom attribute writer method with validation - # @param [Object] url Value to be assigned - def url=(url) - if url.nil? - fail ArgumentError, 'url cannot be nil' - end - - pattern = Regexp.new(/^https:\/\//) - if url !~ pattern - fail ArgumentError, "invalid value for \"url\", must conform to the pattern #{pattern}." - end - - @url = url - end - # Checks equality by comparing each attribute. # @param [Object] Object to be compared def ==(o) diff --git a/generated/activitysmith_openapi/models/live_activity_alert_badge.rb b/generated/activitysmith_openapi/models/live_activity_alert_badge.rb index 74c37f2..9dd32be 100644 --- a/generated/activitysmith_openapi/models/live_activity_alert_badge.rb +++ b/generated/activitysmith_openapi/models/live_activity_alert_badge.rb @@ -14,7 +14,7 @@ require 'time' module OpenapiClient - # Optional badge for Alert Live Activities. + # Optional badge for Live Activities. class LiveActivityAlertBadge attr_accessor :title diff --git a/generated/activitysmith_openapi/models/live_activity_alert_icon.rb b/generated/activitysmith_openapi/models/live_activity_alert_icon.rb index b8797fb..829a322 100644 --- a/generated/activitysmith_openapi/models/live_activity_alert_icon.rb +++ b/generated/activitysmith_openapi/models/live_activity_alert_icon.rb @@ -14,7 +14,7 @@ require 'time' module OpenapiClient - # Optional SF Symbol icon for Alert Live Activities. + # Optional SF Symbol icon for Live Activities. class LiveActivityAlertIcon # Apple SF Symbol name. attr_accessor :symbol diff --git a/generated/activitysmith_openapi/models/push_notification_action.rb b/generated/activitysmith_openapi/models/push_notification_action.rb index 8781a47..1238aeb 100644 --- a/generated/activitysmith_openapi/models/push_notification_action.rb +++ b/generated/activitysmith_openapi/models/push_notification_action.rb @@ -20,7 +20,7 @@ class PushNotificationAction attr_accessor :type - # HTTPS URL. For open_url it is opened in browser. For webhook it is called by ActivitySmith backend. + # Action URL. For open_url, use an HTTPS or shortcuts:// URL. For webhook, use an HTTPS URL called by the ActivitySmith backend. attr_accessor :url # Webhook HTTP method. Used only when type=webhook. @@ -29,28 +29,6 @@ class PushNotificationAction # Optional webhook payload body. Used only when type=webhook. attr_accessor :body - class EnumAttributeValidator - attr_reader :datatype - attr_reader :allowable_values - - def initialize(datatype, allowable_values) - @allowable_values = allowable_values.map do |value| - case datatype.to_s - when /Integer/i - value.to_i - when /Float/i - value.to_f - else - value - end - end - end - - def valid?(value) - !value || allowable_values.include?(value) - end - end - # Attribute mapping from ruby-style variable name to JSON key. def self.attribute_map { @@ -116,6 +94,7 @@ def initialize(attributes = {}) else self.url = nil end + validate_action_url! if attributes.key?(:'method') self.method = attributes[:'method'] @@ -130,6 +109,16 @@ def initialize(attributes = {}) end end + def validate_action_url! + return if @url.nil? || @type.nil? + if @type == PushNotificationActionType::OPEN_URL && @url !~ /\A(https|shortcuts):\/\// + fail ArgumentError, 'invalid value for "url", open_url must use https or shortcuts.' + end + if @type == PushNotificationActionType::WEBHOOK && @url !~ /\Ahttps:\/\// + fail ArgumentError, 'invalid value for "url", webhook must use https.' + end + end + # Show invalid properties with the reasons. Usually used together with valid? # @return Array for valid properties with the reasons def list_invalid_properties @@ -146,10 +135,11 @@ def list_invalid_properties if @url.nil? invalid_properties.push('invalid value for "url", url cannot be nil.') end - - pattern = Regexp.new(/^https:\/\//) - if @url !~ pattern - invalid_properties.push("invalid value for \"url\", must conform to the pattern #{pattern}.") + if !@url.nil? && @type == PushNotificationActionType::OPEN_URL && @url !~ /\A(https|shortcuts):\/\// + invalid_properties.push('invalid value for "url", open_url must use https or shortcuts.') + end + if !@url.nil? && @type == PushNotificationActionType::WEBHOOK && @url !~ /\Ahttps:\/\// + invalid_properties.push('invalid value for "url", webhook must use https.') end invalid_properties @@ -162,25 +152,11 @@ def valid? return false if @title.nil? return false if @type.nil? return false if @url.nil? - return false if @url !~ Regexp.new(/^https:\/\//) + return false if !@url.nil? && @type == PushNotificationActionType::OPEN_URL && @url !~ /\A(https|shortcuts):\/\// + return false if !@url.nil? && @type == PushNotificationActionType::WEBHOOK && @url !~ /\Ahttps:\/\// true end - # Custom attribute writer method with validation - # @param [Object] url Value to be assigned - def url=(url) - if url.nil? - fail ArgumentError, 'url cannot be nil' - end - - pattern = Regexp.new(/^https:\/\//) - if url !~ pattern - fail ArgumentError, "invalid value for \"url\", must conform to the pattern #{pattern}." - end - - @url = url - end - # Checks equality by comparing each attribute. # @param [Object] Object to be compared def ==(o) diff --git a/generated/activitysmith_openapi/models/push_notification_request.rb b/generated/activitysmith_openapi/models/push_notification_request.rb index c9159f0..d15ad5b 100644 --- a/generated/activitysmith_openapi/models/push_notification_request.rb +++ b/generated/activitysmith_openapi/models/push_notification_request.rb @@ -24,7 +24,7 @@ class PushNotificationRequest # Optional HTTPS URL for an image, audio file, or video that users can preview or play when they expand the notification. If `redirection` is omitted, tapping the notification opens this URL. Cannot be combined with `actions`. attr_accessor :media - # Optional HTTPS URL opened when user taps the notification body. Overrides the default tap target from `media` when both are provided. + # Optional HTTPS or shortcuts:// URL opened when user taps the notification body. Overrides the default tap target from `media` when both are provided. attr_accessor :redirection # Optional interactive actions shown when users expand the notification. Cannot be combined with `media`. @@ -157,7 +157,7 @@ def list_invalid_properties invalid_properties.push("invalid value for \"media\", must conform to the pattern #{pattern}.") end - pattern = Regexp.new(/^https:\/\//) + pattern = Regexp.new(/^(https|shortcuts):\/\//) if !@redirection.nil? && @redirection !~ pattern invalid_properties.push("invalid value for \"redirection\", must conform to the pattern #{pattern}.") end @@ -175,7 +175,7 @@ def valid? warn '[DEPRECATED] the `valid?` method is obsolete' return false if @title.nil? return false if !@media.nil? && @media !~ Regexp.new(/^https:\/\//) - return false if !@redirection.nil? && @redirection !~ Regexp.new(/^https:\/\//) + return false if !@redirection.nil? && @redirection !~ Regexp.new(/^(https|shortcuts):\/\//) return false if !@actions.nil? && @actions.length > 4 true end @@ -202,7 +202,7 @@ def redirection=(redirection) fail ArgumentError, 'redirection cannot be nil' end - pattern = Regexp.new(/^https:\/\//) + pattern = Regexp.new(/^(https|shortcuts):\/\//) if redirection !~ pattern fail ArgumentError, "invalid value for \"redirection\", must conform to the pattern #{pattern}." end diff --git a/generated/activitysmith_openapi/models/stream_content_state.rb b/generated/activitysmith_openapi/models/stream_content_state.rb index b0da70c..8597f4d 100644 --- a/generated/activitysmith_openapi/models/stream_content_state.rb +++ b/generated/activitysmith_openapi/models/stream_content_state.rb @@ -53,10 +53,10 @@ class StreamContentState # Required for type=alert. attr_accessor :message - # Optional SF Symbol icon for type=alert. + # Optional SF Symbol icon. Supported by alert, progress, segmented_progress, metrics, and stats. attr_accessor :icon - # Optional badge for type=alert. + # Optional badge. Supported by alert, progress, and segmented_progress. attr_accessor :badge # Optional. Seconds before the ended Live Activity is dismissed. diff --git a/test/resources_test.rb b/test/resources_test.rb index 1a51514..534d454 100644 --- a/test/resources_test.rb +++ b/test/resources_test.rb @@ -1,6 +1,11 @@ # frozen_string_literal: true require_relative "test_helper" +require File.expand_path("../generated/activitysmith_openapi/models/live_activity_action", __dir__) +require File.expand_path("../generated/activitysmith_openapi/models/live_activity_action_type", __dir__) +require File.expand_path("../generated/activitysmith_openapi/models/push_notification_action", __dir__) +require File.expand_path("../generated/activitysmith_openapi/models/push_notification_action_type", __dir__) +require File.expand_path("../generated/activitysmith_openapi/models/push_notification_request", __dir__) class FakePushApi attr_reader :calls @@ -117,10 +122,22 @@ def test_notifications_preserve_media_and_redirection } resource.send(payload) + resource.send( + title: "Run Shortcut", + redirection: "shortcuts://run-shortcut?name=Jarvis" + ) assert_equal( [ - [:send_push_notification, payload, {}] + [:send_push_notification, payload, {}], + [ + :send_push_notification, + { + title: "Run Shortcut", + redirection: "shortcuts://run-shortcut?name=Jarvis" + }, + {} + ] ], api.calls ) @@ -144,6 +161,80 @@ def test_notifications_reject_media_and_actions assert_empty api.calls end + def test_notifications_preserve_shortcuts_open_url_actions + api = FakePushApi.new + resource = ActivitySmith::Notifications.new(api) + + payload = { + title: "Task finished", + actions: [ + { + title: "Run Shortcut", + type: "open_url", + url: "shortcuts://run-shortcut?name=Jarvis" + } + ] + } + + resource.send(payload) + + assert_equal( + [ + [:send_push_notification, payload, {}] + ], + api.calls + ) + end + + def test_generated_push_notification_open_url_allows_shortcuts + action = OpenapiClient::PushNotificationAction.new( + title: "Chat", + type: OpenapiClient::PushNotificationActionType::OPEN_URL, + url: "shortcuts://run-shortcut?name=JARVIS" + ) + + assert action.valid? + end + + def test_generated_push_notification_webhook_rejects_shortcuts + assert_raises(ArgumentError) do + OpenapiClient::PushNotificationAction.new( + title: "Chat", + type: OpenapiClient::PushNotificationActionType::WEBHOOK, + url: "shortcuts://run-shortcut?name=JARVIS" + ) + end + end + + def test_generated_push_notification_redirection_allows_shortcuts + request = OpenapiClient::PushNotificationRequest.new( + title: "Task finished", + redirection: "shortcuts://run-shortcut?name=Jarvis" + ) + + assert request.valid? + end + + def test_generated_live_activity_open_url_allows_shortcuts + action = OpenapiClient::LiveActivityAction.new( + title: "Chat", + type: OpenapiClient::LiveActivityActionType::OPEN_URL, + url: "shortcuts://run-shortcut?name=JARVIS" + ) + + assert action.valid? + end + + def test_generated_live_activity_webhook_rejects_shortcuts + assert_raises(ArgumentError) do + OpenapiClient::LiveActivityAction.new( + title: "Chat", + type: OpenapiClient::LiveActivityActionType::WEBHOOK, + url: "shortcuts://run-shortcut?name=JARVIS" + ) + end + end + def test_live_activities_short_and_legacy_methods api = FakeLiveApi.new resource = ActivitySmith::LiveActivities.new(api) @@ -310,6 +401,66 @@ def test_live_activities_support_alert_helpers ) end + def test_live_activities_support_icon_and_badge_on_non_alert_types + api = FakeLiveApi.new + resource = ActivitySmith::LiveActivities.new(api) + + resource.stream( + "prod-web-1", + content_state: ActivitySmith::LiveActivities.content_state( + title: "Server Health", + subtitle: "prod-web-1", + type: ActivitySmith::LiveActivities::TYPE_METRICS, + icon: ActivitySmith::LiveActivities.alert_icon("server.rack", color: "blue"), + metrics: [{ label: "CPU", value: 18, unit: "%" }] + ) + ) + resource.stream( + "nightly-database-backup", + content_state: ActivitySmith::LiveActivities.content_state( + title: "Nightly Database Backup", + subtitle: "verify restore", + type: ActivitySmith::LiveActivities::TYPE_PROGRESS, + badge: ActivitySmith::LiveActivities.alert_badge("S3", color: "cyan"), + percentage: 62 + ) + ) + + assert_equal( + [ + [ + :reconcile_live_activity_stream, + "prod-web-1", + { + content_state: { + title: "Server Health", + subtitle: "prod-web-1", + type: ActivitySmith::LiveActivities::TYPE_METRICS, + icon: { symbol: "server.rack", color: "blue" }, + metrics: [{ label: "CPU", value: 18, unit: "%" }] + } + }, + {} + ], + [ + :reconcile_live_activity_stream, + "nightly-database-backup", + { + content_state: { + title: "Nightly Database Backup", + subtitle: "verify restore", + type: ActivitySmith::LiveActivities::TYPE_PROGRESS, + badge: { title: "S3", color: "cyan" }, + percentage: 62 + } + }, + {} + ] + ], + api.calls + ) + end + def test_live_activities_stream_short_and_legacy_methods api = FakeLiveApi.new resource = ActivitySmith::LiveActivities.new(api) @@ -405,7 +556,7 @@ def test_live_activities_pass_action_payloads_through action: { title: "Open Workflow", type: "open_url", - url: "https://github.com/acme/payments-api/actions/runs/1234567890" + url: "shortcuts://run-shortcut?name=Deploy%20Status" } } @@ -439,7 +590,7 @@ def test_live_activities_pass_action_payloads_through action: { title: "Open Workflow", type: "open_url", - url: "https://github.com/acme/payments-api/actions/runs/1234567890" + url: "shortcuts://run-shortcut?name=Deploy%20Status" } }