diff --git a/README.md b/README.md
index 4512559..4d67586 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)
@@ -35,6 +37,7 @@ composer require activitysmith/activitysmith
declare(strict_types=1);
use ActivitySmith\ActivitySmith;
+use ActivitySmith\LiveActivities;
use ActivitySmith\LiveActivityAction;
use ActivitySmith\LiveActivityAlertBadge;
use ActivitySmith\LiveActivityAlertIcon;
@@ -258,14 +261,6 @@ $activitysmith->liveActivities->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 `endStream(...)` with the same `streamKey` 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 `autoDismissMinutes` to choose a different dismissal time, including `0` for immediate dismissal.
@@ -346,6 +341,75 @@ $activitysmith->liveActivities->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`.
+
+
+
+
+
+```php
+$activitysmith->liveActivities->stream(
+ 'prod-web-1',
+ contentState: LiveActivityContentState::make(
+ title: 'Server Health',
+ subtitle: 'prod-web-1',
+ type: LiveActivities::TYPE_METRICS,
+ icon: LiveActivityAlertIcon::make(symbol: 'server.rack', color: 'blue'),
+ metrics: [
+ LiveActivityMetric::make(label: 'CPU', value: 18, unit: '%'),
+ LiveActivityMetric::make(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.
+
+
+
+
+
+```php
+$activitysmith->liveActivities->stream(
+ 'nightly-database-backup',
+ contentState: LiveActivityContentState::make(
+ title: 'Nightly Database Backup',
+ subtitle: 'verify restore',
+ type: LiveActivities::TYPE_PROGRESS,
+ badge: LiveActivityAlertBadge::make(title: '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/Model/ContentStateEnd.php b/generated/Model/ContentStateEnd.php
index 2d24d1f..8b7d979 100644
--- a/generated/Model/ContentStateEnd.php
+++ b/generated/Model/ContentStateEnd.php
@@ -35,7 +35,7 @@
* ContentStateEnd Class Doc Comment
*
* @category Class
- * @description 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.
+ * @description 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.
* @package ActivitySmith\Generated
* @author OpenAPI Generator team
* @link https://openapi-generator.tech
@@ -857,7 +857,7 @@ public function getIcon()
/**
* Sets icon
*
- * @param \ActivitySmith\Generated\Model\LiveActivityAlertIcon|null $icon Optional SF Symbol icon for type=alert.
+ * @param \ActivitySmith\Generated\Model\LiveActivityAlertIcon|null $icon Optional SF Symbol icon. Supported by alert, progress, segmented_progress, metrics, and stats.
*
* @return self
*/
@@ -884,7 +884,7 @@ public function getBadge()
/**
* Sets badge
*
- * @param \ActivitySmith\Generated\Model\LiveActivityAlertBadge|null $badge Optional badge for type=alert.
+ * @param \ActivitySmith\Generated\Model\LiveActivityAlertBadge|null $badge Optional badge. Supported by alert, progress, and segmented_progress.
*
* @return self
*/
diff --git a/generated/Model/ContentStateStart.php b/generated/Model/ContentStateStart.php
index 5f9839c..1a6f499 100644
--- a/generated/Model/ContentStateStart.php
+++ b/generated/Model/ContentStateStart.php
@@ -35,7 +35,7 @@
* ContentStateStart Class Doc Comment
*
* @category Class
- * @description 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.
+ * @description 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.
* @package ActivitySmith\Generated
* @author OpenAPI Generator team
* @link https://openapi-generator.tech
@@ -849,7 +849,7 @@ public function getIcon()
/**
* Sets icon
*
- * @param \ActivitySmith\Generated\Model\LiveActivityAlertIcon|null $icon Optional SF Symbol icon for type=alert.
+ * @param \ActivitySmith\Generated\Model\LiveActivityAlertIcon|null $icon Optional SF Symbol icon. Supported by alert, progress, segmented_progress, metrics, and stats.
*
* @return self
*/
@@ -876,7 +876,7 @@ public function getBadge()
/**
* Sets badge
*
- * @param \ActivitySmith\Generated\Model\LiveActivityAlertBadge|null $badge Optional badge for type=alert.
+ * @param \ActivitySmith\Generated\Model\LiveActivityAlertBadge|null $badge Optional badge. Supported by alert, progress, and segmented_progress.
*
* @return self
*/
diff --git a/generated/Model/ContentStateUpdate.php b/generated/Model/ContentStateUpdate.php
index 428819c..33cb40f 100644
--- a/generated/Model/ContentStateUpdate.php
+++ b/generated/Model/ContentStateUpdate.php
@@ -35,7 +35,7 @@
* ContentStateUpdate Class Doc Comment
*
* @category Class
- * @description 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.
+ * @description 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.
* @package ActivitySmith\Generated
* @author OpenAPI Generator team
* @link https://openapi-generator.tech
@@ -846,7 +846,7 @@ public function getIcon()
/**
* Sets icon
*
- * @param \ActivitySmith\Generated\Model\LiveActivityAlertIcon|null $icon Optional SF Symbol icon for type=alert.
+ * @param \ActivitySmith\Generated\Model\LiveActivityAlertIcon|null $icon Optional SF Symbol icon. Supported by alert, progress, segmented_progress, metrics, and stats.
*
* @return self
*/
@@ -873,7 +873,7 @@ public function getBadge()
/**
* Sets badge
*
- * @param \ActivitySmith\Generated\Model\LiveActivityAlertBadge|null $badge Optional badge for type=alert.
+ * @param \ActivitySmith\Generated\Model\LiveActivityAlertBadge|null $badge Optional badge. Supported by alert, progress, and segmented_progress.
*
* @return self
*/
diff --git a/generated/Model/LiveActivityAction.php b/generated/Model/LiveActivityAction.php
index f1030bc..88539d3 100644
--- a/generated/Model/LiveActivityAction.php
+++ b/generated/Model/LiveActivityAction.php
@@ -312,10 +312,15 @@ public function listInvalidProperties()
if ($this->container['url'] === null) {
$invalidProperties[] = "'url' can't be null";
}
- if (!preg_match("/^https:\/\//", $this->container['url'])) {
- $invalidProperties[] = "invalid value for 'url', must be conform to the pattern /^https:\/\//.";
+ if ($this->container['url'] !== null) {
+ $actionType = $this->container['type'];
+ if ($actionType === LiveActivityActionType::OPEN_URL && !preg_match('/^(https|shortcuts):\/\//', (string) $this->container['url'])) {
+ $invalidProperties[] = "invalid value for 'url', open_url must use https or shortcuts.";
+ }
+ if ($actionType === LiveActivityActionType::WEBHOOK && !preg_match('/^https:\/\//', (string) $this->container['url'])) {
+ $invalidProperties[] = "invalid value for 'url', webhook must use https.";
+ }
}
-
return $invalidProperties;
}
@@ -398,7 +403,7 @@ public function getUrl()
/**
* Sets url
*
- * @param string $url HTTPS URL. For open_url it is opened in browser. For webhook it is called by ActivitySmith backend.
+ * @param string $url Action URL. For open_url, use an HTTPS or shortcuts:// URL. For webhook, use an HTTPS URL called by the ActivitySmith backend.
*
* @return self
*/
@@ -407,11 +412,13 @@ public function setUrl($url)
if (is_null($url)) {
throw new \InvalidArgumentException('non-nullable url cannot be null');
}
-
- if ((!preg_match("/^https:\/\//", ObjectSerializer::toString($url)))) {
- throw new \InvalidArgumentException("invalid value for \$url when calling LiveActivityAction., must conform to the pattern /^https:\/\//.");
+ $actionType = $this->container['type'] ?? null;
+ if ($actionType === LiveActivityActionType::OPEN_URL && !preg_match('/^(https|shortcuts):\/\//', (string) $url)) {
+ throw new \InvalidArgumentException("invalid value for \$url when calling LiveActivityAction., open_url must use https or shortcuts.");
+ }
+ if ($actionType === LiveActivityActionType::WEBHOOK && !preg_match('/^https:\/\//', (string) $url)) {
+ throw new \InvalidArgumentException("invalid value for \$url when calling LiveActivityAction., webhook must use https.");
}
-
$this->container['url'] = $url;
return $this;
@@ -561,4 +568,3 @@ public function toHeaderValue()
}
}
-
diff --git a/generated/Model/LiveActivityAlertBadge.php b/generated/Model/LiveActivityAlertBadge.php
index 39947fb..00515f3 100644
--- a/generated/Model/LiveActivityAlertBadge.php
+++ b/generated/Model/LiveActivityAlertBadge.php
@@ -35,7 +35,7 @@
* LiveActivityAlertBadge Class Doc Comment
*
* @category Class
- * @description Optional badge for Alert Live Activities.
+ * @description Optional badge for Live Activities.
* @package ActivitySmith\Generated
* @author OpenAPI Generator team
* @link https://openapi-generator.tech
diff --git a/generated/Model/LiveActivityAlertIcon.php b/generated/Model/LiveActivityAlertIcon.php
index 884ebe6..af5474c 100644
--- a/generated/Model/LiveActivityAlertIcon.php
+++ b/generated/Model/LiveActivityAlertIcon.php
@@ -35,7 +35,7 @@
* LiveActivityAlertIcon Class Doc Comment
*
* @category Class
- * @description Optional SF Symbol icon for Alert Live Activities.
+ * @description Optional SF Symbol icon for Live Activities.
* @package ActivitySmith\Generated
* @author OpenAPI Generator team
* @link https://openapi-generator.tech
diff --git a/generated/Model/PushNotificationAction.php b/generated/Model/PushNotificationAction.php
index 4888f80..04e9cb9 100644
--- a/generated/Model/PushNotificationAction.php
+++ b/generated/Model/PushNotificationAction.php
@@ -311,10 +311,15 @@ public function listInvalidProperties()
if ($this->container['url'] === null) {
$invalidProperties[] = "'url' can't be null";
}
- if (!preg_match("/^https:\/\//", $this->container['url'])) {
- $invalidProperties[] = "invalid value for 'url', must be conform to the pattern /^https:\/\//.";
+ if ($this->container['url'] !== null) {
+ $actionType = $this->container['type'];
+ if ($actionType === PushNotificationActionType::OPEN_URL && !preg_match('/^(https|shortcuts):\/\//', (string) $this->container['url'])) {
+ $invalidProperties[] = "invalid value for 'url', open_url must use https or shortcuts.";
+ }
+ if ($actionType === PushNotificationActionType::WEBHOOK && !preg_match('/^https:\/\//', (string) $this->container['url'])) {
+ $invalidProperties[] = "invalid value for 'url', webhook must use https.";
+ }
}
-
return $invalidProperties;
}
@@ -397,7 +402,7 @@ public function getUrl()
/**
* Sets url
*
- * @param string $url HTTPS URL. For open_url it is opened in browser. For webhook it is called by ActivitySmith backend.
+ * @param string $url Action URL. For open_url, use an HTTPS or shortcuts:// URL. For webhook, use an HTTPS URL called by the ActivitySmith backend.
*
* @return self
*/
@@ -406,11 +411,13 @@ public function setUrl($url)
if (is_null($url)) {
throw new \InvalidArgumentException('non-nullable url cannot be null');
}
-
- if ((!preg_match("/^https:\/\//", ObjectSerializer::toString($url)))) {
- throw new \InvalidArgumentException("invalid value for \$url when calling PushNotificationAction., must conform to the pattern /^https:\/\//.");
+ $actionType = $this->container['type'] ?? null;
+ if ($actionType === PushNotificationActionType::OPEN_URL && !preg_match('/^(https|shortcuts):\/\//', (string) $url)) {
+ throw new \InvalidArgumentException("invalid value for \$url when calling PushNotificationAction., open_url must use https or shortcuts.");
+ }
+ if ($actionType === PushNotificationActionType::WEBHOOK && !preg_match('/^https:\/\//', (string) $url)) {
+ throw new \InvalidArgumentException("invalid value for \$url when calling PushNotificationAction., webhook must use https.");
}
-
$this->container['url'] = $url;
return $this;
@@ -560,4 +567,3 @@ public function toHeaderValue()
}
}
-
diff --git a/generated/Model/PushNotificationRequest.php b/generated/Model/PushNotificationRequest.php
index 229a7a6..6b05aef 100644
--- a/generated/Model/PushNotificationRequest.php
+++ b/generated/Model/PushNotificationRequest.php
@@ -344,8 +344,8 @@ public function listInvalidProperties()
$invalidProperties[] = "invalid value for 'media', must be conform to the pattern /^https:\/\//.";
}
- if (!is_null($this->container['redirection']) && !preg_match("/^https:\/\//", $this->container['redirection'])) {
- $invalidProperties[] = "invalid value for 'redirection', must be conform to the pattern /^https:\/\//.";
+ if (!is_null($this->container['redirection']) && !preg_match("/^(https|shortcuts):\/\//", $this->container['redirection'])) {
+ $invalidProperties[] = "invalid value for 'redirection', must be conform to the pattern /^(https|shortcuts):\/\//.";
}
if (!is_null($this->container['actions']) && (count($this->container['actions']) > 4)) {
@@ -493,7 +493,7 @@ public function getRedirection()
/**
* Sets redirection
*
- * @param string|null $redirection Optional HTTPS URL opened when user taps the notification body. Overrides the default tap target from `media` when both are provided.
+ * @param string|null $redirection Optional HTTPS or shortcuts:// URL opened when user taps the notification body. Overrides the default tap target from `media` when both are provided.
*
* @return self
*/
@@ -503,8 +503,8 @@ public function setRedirection($redirection)
throw new \InvalidArgumentException('non-nullable redirection cannot be null');
}
- if ((!preg_match("/^https:\/\//", ObjectSerializer::toString($redirection)))) {
- throw new \InvalidArgumentException("invalid value for \$redirection when calling PushNotificationRequest., must conform to the pattern /^https:\/\//.");
+ if ((!preg_match("/^(https|shortcuts):\/\//", ObjectSerializer::toString($redirection)))) {
+ throw new \InvalidArgumentException("invalid value for \$redirection when calling PushNotificationRequest., must conform to the pattern /^(https|shortcuts):\/\//.");
}
$this->container['redirection'] = $redirection;
diff --git a/generated/Model/StreamContentState.php b/generated/Model/StreamContentState.php
index 748be3e..c1e837f 100644
--- a/generated/Model/StreamContentState.php
+++ b/generated/Model/StreamContentState.php
@@ -1015,7 +1015,7 @@ public function getIcon()
/**
* Sets icon
*
- * @param \ActivitySmith\Generated\Model\LiveActivityAlertIcon|null $icon Optional SF Symbol icon for type=alert.
+ * @param \ActivitySmith\Generated\Model\LiveActivityAlertIcon|null $icon Optional SF Symbol icon. Supported by alert, progress, segmented_progress, metrics, and stats.
*
* @return self
*/
@@ -1042,7 +1042,7 @@ public function getBadge()
/**
* Sets badge
*
- * @param \ActivitySmith\Generated\Model\LiveActivityAlertBadge|null $badge Optional badge for type=alert.
+ * @param \ActivitySmith\Generated\Model\LiveActivityAlertBadge|null $badge Optional badge. Supported by alert, progress, and segmented_progress.
*
* @return self
*/
diff --git a/src/LiveActivityColor.php b/src/LiveActivityColor.php
index 521cc08..7d8e040 100644
--- a/src/LiveActivityColor.php
+++ b/src/LiveActivityColor.php
@@ -15,4 +15,5 @@ final class LiveActivityColor
public const RED = 'red';
public const ORANGE = 'orange';
public const YELLOW = 'yellow';
+ public const GRAY = 'gray';
}
diff --git a/tests/ResourcesTest.php b/tests/ResourcesTest.php
index bb12200..0967f47 100644
--- a/tests/ResourcesTest.php
+++ b/tests/ResourcesTest.php
@@ -16,6 +16,11 @@
use ActivitySmith\Generated\Api\LiveActivitiesApi;
use ActivitySmith\Generated\Api\MetricsApi;
use ActivitySmith\Generated\Api\PushNotificationsApi;
+use ActivitySmith\Generated\Model\LiveActivityAction as GeneratedLiveActivityAction;
+use ActivitySmith\Generated\Model\LiveActivityActionType;
+use ActivitySmith\Generated\Model\PushNotificationAction as GeneratedPushNotificationAction;
+use ActivitySmith\Generated\Model\PushNotificationActionType;
+use ActivitySmith\Generated\Model\PushNotificationRequest as GeneratedPushNotificationRequest;
use PHPUnit\Framework\TestCase;
final class ResourcesTest extends TestCase
@@ -119,7 +124,7 @@ public function testPushActionHelper(): void
PushAction::make(
title: 'Open CRM Profile',
type: 'open_url',
- url: 'https://crm.example.com/customers/cus_9f3a1d'
+ url: 'shortcuts://run-shortcut?name=Open%20CRM'
),
],
)
@@ -134,7 +139,7 @@ public function testPushActionHelper(): void
[
'title' => 'Open CRM Profile',
'type' => 'open_url',
- 'url' => 'https://crm.example.com/customers/cus_9f3a1d',
+ 'url' => 'shortcuts://run-shortcut?name=Open%20CRM',
],
],
],
@@ -145,6 +150,60 @@ public function testPushActionHelper(): void
);
}
+ public function testGeneratedPushNotificationOpenUrlAllowsShortcuts(): void
+ {
+ $action = new GeneratedPushNotificationAction([
+ 'title' => 'Chat',
+ 'type' => PushNotificationActionType::OPEN_URL,
+ 'url' => 'shortcuts://run-shortcut?name=JARVIS',
+ ]);
+
+ $this->assertTrue($action->valid());
+ }
+
+ public function testGeneratedPushNotificationWebhookRejectsShortcuts(): void
+ {
+ $action = new GeneratedPushNotificationAction([
+ 'title' => 'Chat',
+ 'type' => PushNotificationActionType::WEBHOOK,
+ 'url' => 'shortcuts://run-shortcut?name=JARVIS',
+ ]);
+
+ $this->assertFalse($action->valid());
+ }
+
+ public function testGeneratedPushNotificationRedirectionAllowsShortcuts(): void
+ {
+ $request = new GeneratedPushNotificationRequest([
+ 'title' => 'Task finished',
+ 'redirection' => 'shortcuts://run-shortcut?name=Jarvis',
+ ]);
+
+ $this->assertTrue($request->valid());
+ }
+
+ public function testGeneratedLiveActivityOpenUrlAllowsShortcuts(): void
+ {
+ $action = new GeneratedLiveActivityAction([
+ 'title' => 'Chat',
+ 'type' => LiveActivityActionType::OPEN_URL,
+ 'url' => 'shortcuts://run-shortcut?name=JARVIS',
+ ]);
+
+ $this->assertTrue($action->valid());
+ }
+
+ public function testGeneratedLiveActivityWebhookRejectsShortcuts(): void
+ {
+ $action = new GeneratedLiveActivityAction([
+ 'title' => 'Chat',
+ 'type' => LiveActivityActionType::WEBHOOK,
+ 'url' => 'shortcuts://run-shortcut?name=JARVIS',
+ ]);
+
+ $this->assertFalse($action->valid());
+ }
+
public function testNotificationsMapsChannelsToTarget(): void
{
$captured = [];
@@ -185,7 +244,7 @@ public function testNotificationsPreserveMediaAndRedirection(): void
->onlyMethods(['sendPushNotification'])
->getMock();
- $api->expects($this->once())
+ $api->expects($this->exactly(2))
->method('sendPushNotification')
->willReturnCallback(function (...$args) use (&$captured, $response) {
$captured[] = $args;
@@ -200,9 +259,20 @@ public function testNotificationsPreserveMediaAndRedirection(): void
];
$this->assertSame($response, $resource->send($payload));
+ $this->assertSame($response, $resource->send(
+ title: 'Run Shortcut',
+ redirection: 'shortcuts://run-shortcut?name=Jarvis'
+ ));
$this->assertSame(
[
[$payload, PushNotificationsApi::contentTypes['sendPushNotification'][0]],
+ [
+ [
+ 'title' => 'Run Shortcut',
+ 'redirection' => 'shortcuts://run-shortcut?name=Jarvis',
+ ],
+ PushNotificationsApi::contentTypes['sendPushNotification'][0],
+ ],
],
$captured
);
@@ -402,7 +472,7 @@ public function testLiveActivitiesPassActionPayloadsThrough(): void
'action' => [
'title' => 'Open Workflow',
'type' => 'open_url',
- 'url' => 'https://github.com/acme/payments-api/actions/runs/1234567890',
+ 'url' => 'shortcuts://run-shortcut?name=Deploy%20Status',
],
];
@@ -436,7 +506,7 @@ public function testLiveActivitiesPassActionPayloadsThrough(): void
'action' => [
'title' => 'Open Workflow',
'type' => 'open_url',
- 'url' => 'https://github.com/acme/payments-api/actions/runs/1234567890',
+ 'url' => 'shortcuts://run-shortcut?name=Deploy%20Status',
],
];
@@ -587,6 +657,79 @@ public function testLiveActivitiesSupportAlertHelpers(): void
);
}
+ public function testLiveActivitiesSupportIconAndBadgeOnNonAlertTypes(): void
+ {
+ $response = (object) ['success' => true];
+ $captured = [];
+
+ $api = $this->getMockBuilder(LiveActivitiesApi::class)
+ ->disableOriginalConstructor()
+ ->onlyMethods(['reconcileLiveActivityStream'])
+ ->getMock();
+
+ $api->expects($this->exactly(2))
+ ->method('reconcileLiveActivityStream')
+ ->willReturnCallback(function (...$args) use (&$captured, $response) {
+ $captured[] = $args;
+ return $response;
+ });
+
+ $resource = new LiveActivities($api);
+
+ $resource->stream(
+ 'prod-web-1',
+ contentState: LiveActivityContentState::make(
+ title: 'Server Health',
+ subtitle: 'prod-web-1',
+ type: LiveActivities::TYPE_METRICS,
+ icon: LiveActivityAlertIcon::make(symbol: 'server.rack', color: 'blue'),
+ metrics: [LiveActivityMetric::make(label: 'CPU', value: 18, unit: '%')]
+ )
+ );
+ $resource->stream(
+ 'nightly-database-backup',
+ contentState: LiveActivityContentState::make(
+ title: 'Nightly Database Backup',
+ subtitle: 'verify restore',
+ type: LiveActivities::TYPE_PROGRESS,
+ badge: LiveActivityAlertBadge::make(title: 'S3', color: 'cyan'),
+ percentage: 62
+ )
+ );
+
+ $this->assertSame(
+ [
+ [
+ 'prod-web-1',
+ [
+ 'content_state' => [
+ 'title' => 'Server Health',
+ 'subtitle' => 'prod-web-1',
+ 'type' => LiveActivities::TYPE_METRICS,
+ 'icon' => ['symbol' => 'server.rack', 'color' => 'blue'],
+ 'metrics' => [['label' => 'CPU', 'value' => 18, 'unit' => '%']],
+ ],
+ ],
+ LiveActivitiesApi::contentTypes['reconcileLiveActivityStream'][0],
+ ],
+ [
+ 'nightly-database-backup',
+ [
+ 'content_state' => [
+ 'title' => 'Nightly Database Backup',
+ 'subtitle' => 'verify restore',
+ 'type' => LiveActivities::TYPE_PROGRESS,
+ 'badge' => ['title' => 'S3', 'color' => 'cyan'],
+ 'percentage' => 62,
+ ],
+ ],
+ LiveActivitiesApi::contentTypes['reconcileLiveActivityStream'][0],
+ ],
+ ],
+ $captured
+ );
+ }
+
public function testLiveActivitiesBuildRequestsFromNamedFields(): void
{
$response = (object) ['success' => true];
@@ -630,7 +773,7 @@ public function testLiveActivitiesBuildRequestsFromNamedFields(): void
$action = LiveActivityAction::make(
title: 'Open Dashboard',
type: 'open_url',
- url: 'https://ops.example.com/servers/prod-web-1'
+ url: 'shortcuts://run-shortcut?name=Open%20Dashboard'
);
$state = LiveActivityContentState::make(
title: 'Server Health',