diff --git a/README.md b/README.md
index 60ee536..6f6b5cc 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,8 @@ See the [API reference](https://activitysmith.com/docs/api-reference/introductio
- [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)
@@ -266,14 +268,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.
@@ -354,6 +348,67 @@ 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`.
+
+
+
+
+
+```python
+activitysmith.live_activities.stream(
+ "prod-web-1",
+ content_state=content_state(
+ title="Server Health",
+ subtitle="prod-web-1",
+ type=activitysmith.live_activities.TYPE_METRICS,
+ icon=alert_icon("server.rack", color="blue"),
+ metrics=[
+ metric(label="CPU", value=18, unit="%"),
+ metric(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.
+
+
+
+
+
+```python
+activitysmith.live_activities.stream(
+ "nightly-database-backup",
+ content_state=content_state(
+ title="Nightly Database Backup",
+ subtitle="verify restore",
+ type=activitysmith.live_activities.TYPE_PROGRESS,
+ badge=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/activitysmith_openapi/docs/ContentStateEnd.md b/activitysmith_openapi/docs/ContentStateEnd.md
index 65bc34e..c608784 100644
--- a/activitysmith_openapi/docs/ContentStateEnd.md
+++ b/activitysmith_openapi/docs/ContentStateEnd.md
@@ -1,6 +1,6 @@
# ContentStateEnd
-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.
## Properties
@@ -15,8 +15,8 @@ Name | Type | Description | Notes
**upper_limit** | **float** | Maximum progress value. Use with value for type=progress. | [optional]
**metrics** | [**List[ActivityMetric]**](ActivityMetric.md) | Use for type=metrics or type=stats. | [optional]
**message** | **str** | Alert message. Use for type=alert. | [optional]
-**icon** | [**LiveActivityAlertIcon**](LiveActivityAlertIcon.md) | Optional SF Symbol icon for type=alert. | [optional]
-**badge** | [**LiveActivityAlertBadge**](LiveActivityAlertBadge.md) | Optional badge for type=alert. | [optional]
+**icon** | [**LiveActivityAlertIcon**](LiveActivityAlertIcon.md) | Optional SF Symbol icon. Supported by alert, progress, segmented_progress, metrics, and stats. | [optional]
+**badge** | [**LiveActivityAlertBadge**](LiveActivityAlertBadge.md) | Optional badge. Supported by alert, progress, and segmented_progress. | [optional]
**type** | **str** | Optional. When omitted, the API uses the existing Live Activity type. | [optional]
**color** | **str** | Optional. Accent color for progress, segmented_progress, and metrics Live Activities. For Alert Live Activities, this tints the action button when action is included. | [optional]
**step_color** | **str** | Optional. Overrides color for the current step. Only applies to type=segmented_progress. | [optional]
diff --git a/activitysmith_openapi/docs/ContentStateStart.md b/activitysmith_openapi/docs/ContentStateStart.md
index 779b022..6036e3f 100644
--- a/activitysmith_openapi/docs/ContentStateStart.md
+++ b/activitysmith_openapi/docs/ContentStateStart.md
@@ -1,6 +1,6 @@
# ContentStateStart
-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.
## Properties
@@ -15,8 +15,8 @@ Name | Type | Description | Notes
**upper_limit** | **float** | Maximum progress value. Use with value for type=progress. | [optional]
**metrics** | [**List[ActivityMetric]**](ActivityMetric.md) | Use for type=metrics or type=stats. | [optional]
**message** | **str** | Required for type=alert. | [optional]
-**icon** | [**LiveActivityAlertIcon**](LiveActivityAlertIcon.md) | Optional SF Symbol icon for type=alert. | [optional]
-**badge** | [**LiveActivityAlertBadge**](LiveActivityAlertBadge.md) | Optional badge for type=alert. | [optional]
+**icon** | [**LiveActivityAlertIcon**](LiveActivityAlertIcon.md) | Optional SF Symbol icon. Supported by alert, progress, segmented_progress, metrics, and stats. | [optional]
+**badge** | [**LiveActivityAlertBadge**](LiveActivityAlertBadge.md) | Optional badge. Supported by alert, progress, and segmented_progress. | [optional]
**type** | **str** | |
**color** | **str** | Optional. Accent color for progress, segmented_progress, and metrics Live Activities. For Alert Live Activities, this tints the action button when action is included. | [optional]
**step_color** | **str** | Optional. Overrides color for the current step. Only applies to type=segmented_progress. | [optional]
diff --git a/activitysmith_openapi/docs/ContentStateUpdate.md b/activitysmith_openapi/docs/ContentStateUpdate.md
index 8653ffe..d506517 100644
--- a/activitysmith_openapi/docs/ContentStateUpdate.md
+++ b/activitysmith_openapi/docs/ContentStateUpdate.md
@@ -1,6 +1,6 @@
# ContentStateUpdate
-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.
## Properties
@@ -15,8 +15,8 @@ Name | Type | Description | Notes
**upper_limit** | **float** | Maximum progress value. Use with value for type=progress. | [optional]
**metrics** | [**List[ActivityMetric]**](ActivityMetric.md) | Use for type=metrics or type=stats. | [optional]
**message** | **str** | Alert message. Use for type=alert. | [optional]
-**icon** | [**LiveActivityAlertIcon**](LiveActivityAlertIcon.md) | Optional SF Symbol icon for type=alert. | [optional]
-**badge** | [**LiveActivityAlertBadge**](LiveActivityAlertBadge.md) | Optional badge for type=alert. | [optional]
+**icon** | [**LiveActivityAlertIcon**](LiveActivityAlertIcon.md) | Optional SF Symbol icon. Supported by alert, progress, segmented_progress, metrics, and stats. | [optional]
+**badge** | [**LiveActivityAlertBadge**](LiveActivityAlertBadge.md) | Optional badge. Supported by alert, progress, and segmented_progress. | [optional]
**type** | **str** | Optional. When omitted, the API uses the existing Live Activity type. | [optional]
**color** | **str** | Optional. Accent color for progress, segmented_progress, and metrics Live Activities. For Alert Live Activities, this tints the action button when action is included. | [optional]
**step_color** | **str** | Optional. Overrides color for the current step. Only applies to type=segmented_progress. | [optional]
diff --git a/activitysmith_openapi/docs/LiveActivityAction.md b/activitysmith_openapi/docs/LiveActivityAction.md
index cdfb25a..324c623 100644
--- a/activitysmith_openapi/docs/LiveActivityAction.md
+++ b/activitysmith_openapi/docs/LiveActivityAction.md
@@ -8,7 +8,7 @@ Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**title** | **str** | Button title displayed in the Live Activity UI. |
**type** | [**LiveActivityActionType**](LiveActivityActionType.md) | |
-**url** | **str** | HTTPS URL. For open_url it is opened in browser. For webhook it is called by ActivitySmith backend. |
+**url** | **str** | Action URL. For open_url, use an HTTPS or shortcuts:// URL. For webhook, use an HTTPS URL called by the ActivitySmith backend. |
**method** | [**LiveActivityWebhookMethod**](LiveActivityWebhookMethod.md) | Webhook HTTP method. Used only when type=webhook. | [optional] [default to LiveActivityWebhookMethod.POST]
**body** | **Dict[str, object]** | Optional webhook payload body. Used only when type=webhook. | [optional]
diff --git a/activitysmith_openapi/docs/LiveActivityAlertBadge.md b/activitysmith_openapi/docs/LiveActivityAlertBadge.md
index 81fc3e0..a1b109c 100644
--- a/activitysmith_openapi/docs/LiveActivityAlertBadge.md
+++ b/activitysmith_openapi/docs/LiveActivityAlertBadge.md
@@ -1,6 +1,6 @@
# LiveActivityAlertBadge
-Optional badge for Alert Live Activities.
+Optional badge for Live Activities.
## Properties
diff --git a/activitysmith_openapi/docs/LiveActivityAlertIcon.md b/activitysmith_openapi/docs/LiveActivityAlertIcon.md
index fa25371..c6d0f9f 100644
--- a/activitysmith_openapi/docs/LiveActivityAlertIcon.md
+++ b/activitysmith_openapi/docs/LiveActivityAlertIcon.md
@@ -1,6 +1,6 @@
# LiveActivityAlertIcon
-Optional SF Symbol icon for Alert Live Activities.
+Optional SF Symbol icon for Live Activities.
## Properties
diff --git a/activitysmith_openapi/docs/PushNotificationAction.md b/activitysmith_openapi/docs/PushNotificationAction.md
index ce17011..1bebd5c 100644
--- a/activitysmith_openapi/docs/PushNotificationAction.md
+++ b/activitysmith_openapi/docs/PushNotificationAction.md
@@ -7,7 +7,7 @@ Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**title** | **str** | Button title displayed in iOS expanded notification UI. |
**type** | [**PushNotificationActionType**](PushNotificationActionType.md) | |
-**url** | **str** | HTTPS URL. For open_url it is opened in browser. For webhook it is called by ActivitySmith backend. |
+**url** | **str** | Action URL. For open_url, use an HTTPS or shortcuts:// URL. For webhook, use an HTTPS URL called by the ActivitySmith backend. |
**method** | [**PushNotificationWebhookMethod**](PushNotificationWebhookMethod.md) | Webhook HTTP method. Used only when type=webhook. | [optional] [default to PushNotificationWebhookMethod.POST]
**body** | **Dict[str, object]** | Optional webhook payload body. Used only when type=webhook. | [optional]
diff --git a/activitysmith_openapi/docs/PushNotificationRequest.md b/activitysmith_openapi/docs/PushNotificationRequest.md
index ef00359..5cde2eb 100644
--- a/activitysmith_openapi/docs/PushNotificationRequest.md
+++ b/activitysmith_openapi/docs/PushNotificationRequest.md
@@ -9,7 +9,7 @@ Name | Type | Description | Notes
**message** | **str** | | [optional]
**subtitle** | **str** | | [optional]
**media** | **str** | 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`. | [optional]
-**redirection** | **str** | Optional HTTPS URL opened when user taps the notification body. Overrides the default tap target from `media` when both are provided. | [optional]
+**redirection** | **str** | Optional HTTPS or shortcuts:// URL opened when user taps the notification body. Overrides the default tap target from `media` when both are provided. | [optional]
**actions** | [**List[PushNotificationAction]**](PushNotificationAction.md) | Optional interactive actions shown when users expand the notification. Cannot be combined with `media`. | [optional]
**payload** | **Dict[str, object]** | | [optional]
**badge** | **int** | | [optional]
diff --git a/activitysmith_openapi/docs/StreamContentState.md b/activitysmith_openapi/docs/StreamContentState.md
index 78f993c..72ae196 100644
--- a/activitysmith_openapi/docs/StreamContentState.md
+++ b/activitysmith_openapi/docs/StreamContentState.md
@@ -19,8 +19,8 @@ Name | Type | Description | Notes
**step_colors** | **List[str]** | Optional. Colors for completed steps. When used with segmented_progress, the array length should match current_step. | [optional]
**metrics** | [**List[ActivityMetric]**](ActivityMetric.md) | Use for metrics and stats activities. | [optional]
**message** | **str** | Required for type=alert. | [optional]
-**icon** | [**LiveActivityAlertIcon**](LiveActivityAlertIcon.md) | Optional SF Symbol icon for type=alert. | [optional]
-**badge** | [**LiveActivityAlertBadge**](LiveActivityAlertBadge.md) | Optional badge for type=alert. | [optional]
+**icon** | [**LiveActivityAlertIcon**](LiveActivityAlertIcon.md) | Optional SF Symbol icon. Supported by alert, progress, segmented_progress, metrics, and stats. | [optional]
+**badge** | [**LiveActivityAlertBadge**](LiveActivityAlertBadge.md) | Optional badge. Supported by alert, progress, and segmented_progress. | [optional]
**auto_dismiss_seconds** | **int** | Optional. Seconds before the ended Live Activity is dismissed. | [optional]
**auto_dismiss_minutes** | **int** | Optional. Minutes before the ended Live Activity is dismissed. | [optional]
diff --git a/activitysmith_openapi/models/content_state_end.py b/activitysmith_openapi/models/content_state_end.py
index 6d0c67b..2e28aa1 100644
--- a/activitysmith_openapi/models/content_state_end.py
+++ b/activitysmith_openapi/models/content_state_end.py
@@ -28,7 +28,7 @@
class ContentStateEnd(BaseModel):
"""
- 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.
""" # noqa: E501
title: StrictStr
subtitle: Optional[StrictStr] = None
@@ -39,8 +39,8 @@ class ContentStateEnd(BaseModel):
upper_limit: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="Maximum progress value. Use with value for type=progress.")
metrics: Optional[Annotated[List[ActivityMetric], Field(min_length=1, max_length=8)]] = Field(default=None, description="Use for type=metrics or type=stats.")
message: Optional[Annotated[str, Field(min_length=1, strict=True)]] = Field(default=None, description="Alert message. Use for type=alert.")
- icon: Optional[LiveActivityAlertIcon] = Field(default=None, description="Optional SF Symbol icon for type=alert.")
- badge: Optional[LiveActivityAlertBadge] = Field(default=None, description="Optional badge for type=alert.")
+ icon: Optional[LiveActivityAlertIcon] = Field(default=None, description="Optional SF Symbol icon. Supported by alert, progress, segmented_progress, metrics, and stats.")
+ badge: Optional[LiveActivityAlertBadge] = Field(default=None, description="Optional badge. Supported by alert, progress, and segmented_progress.")
type: Optional[StrictStr] = Field(default=None, description="Optional. When omitted, the API uses the existing Live Activity type.")
color: Optional[StrictStr] = Field(default=None, description="Optional. Accent color for progress, segmented_progress, and metrics Live Activities. For Alert Live Activities, this tints the action button when action is included.")
step_color: Optional[StrictStr] = Field(default=None, description="Optional. Overrides color for the current step. Only applies to type=segmented_progress.")
diff --git a/activitysmith_openapi/models/content_state_start.py b/activitysmith_openapi/models/content_state_start.py
index 1055dfb..11d2cc0 100644
--- a/activitysmith_openapi/models/content_state_start.py
+++ b/activitysmith_openapi/models/content_state_start.py
@@ -28,7 +28,7 @@
class ContentStateStart(BaseModel):
"""
- 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.
""" # noqa: E501
title: StrictStr
subtitle: Optional[StrictStr] = None
@@ -39,8 +39,8 @@ class ContentStateStart(BaseModel):
upper_limit: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="Maximum progress value. Use with value for type=progress.")
metrics: Optional[Annotated[List[ActivityMetric], Field(min_length=1, max_length=8)]] = Field(default=None, description="Use for type=metrics or type=stats.")
message: Optional[Annotated[str, Field(min_length=1, strict=True)]] = Field(default=None, description="Required for type=alert.")
- icon: Optional[LiveActivityAlertIcon] = Field(default=None, description="Optional SF Symbol icon for type=alert.")
- badge: Optional[LiveActivityAlertBadge] = Field(default=None, description="Optional badge for type=alert.")
+ icon: Optional[LiveActivityAlertIcon] = Field(default=None, description="Optional SF Symbol icon. Supported by alert, progress, segmented_progress, metrics, and stats.")
+ badge: Optional[LiveActivityAlertBadge] = Field(default=None, description="Optional badge. Supported by alert, progress, and segmented_progress.")
type: StrictStr
color: Optional[StrictStr] = Field(default=None, description="Optional. Accent color for progress, segmented_progress, and metrics Live Activities. For Alert Live Activities, this tints the action button when action is included.")
step_color: Optional[StrictStr] = Field(default=None, description="Optional. Overrides color for the current step. Only applies to type=segmented_progress.")
diff --git a/activitysmith_openapi/models/content_state_update.py b/activitysmith_openapi/models/content_state_update.py
index d1f0c3d..08c7972 100644
--- a/activitysmith_openapi/models/content_state_update.py
+++ b/activitysmith_openapi/models/content_state_update.py
@@ -28,7 +28,7 @@
class ContentStateUpdate(BaseModel):
"""
- 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.
""" # noqa: E501
title: StrictStr
subtitle: Optional[StrictStr] = None
@@ -39,8 +39,8 @@ class ContentStateUpdate(BaseModel):
upper_limit: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="Maximum progress value. Use with value for type=progress.")
metrics: Optional[Annotated[List[ActivityMetric], Field(min_length=1, max_length=8)]] = Field(default=None, description="Use for type=metrics or type=stats.")
message: Optional[Annotated[str, Field(min_length=1, strict=True)]] = Field(default=None, description="Alert message. Use for type=alert.")
- icon: Optional[LiveActivityAlertIcon] = Field(default=None, description="Optional SF Symbol icon for type=alert.")
- badge: Optional[LiveActivityAlertBadge] = Field(default=None, description="Optional badge for type=alert.")
+ icon: Optional[LiveActivityAlertIcon] = Field(default=None, description="Optional SF Symbol icon. Supported by alert, progress, segmented_progress, metrics, and stats.")
+ badge: Optional[LiveActivityAlertBadge] = Field(default=None, description="Optional badge. Supported by alert, progress, and segmented_progress.")
type: Optional[StrictStr] = Field(default=None, description="Optional. When omitted, the API uses the existing Live Activity type.")
color: Optional[StrictStr] = Field(default=None, description="Optional. Accent color for progress, segmented_progress, and metrics Live Activities. For Alert Live Activities, this tints the action button when action is included.")
step_color: Optional[StrictStr] = Field(default=None, description="Optional. Overrides color for the current step. Only applies to type=segmented_progress.")
diff --git a/activitysmith_openapi/models/live_activity_action.py b/activitysmith_openapi/models/live_activity_action.py
index f75137c..544bf0a 100644
--- a/activitysmith_openapi/models/live_activity_action.py
+++ b/activitysmith_openapi/models/live_activity_action.py
@@ -17,9 +17,8 @@
import re # noqa: F401
import json
-from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator
+from pydantic import BaseModel, ConfigDict, Field, StrictStr, model_validator
from typing import Any, ClassVar, Dict, List, Optional
-from typing_extensions import Annotated
from activitysmith_openapi.models.live_activity_action_type import LiveActivityActionType
from activitysmith_openapi.models.live_activity_webhook_method import LiveActivityWebhookMethod
from typing import Optional, Set
@@ -31,18 +30,11 @@ class LiveActivityAction(BaseModel):
""" # noqa: E501
title: StrictStr = Field(description="Button title displayed in the Live Activity UI.")
type: LiveActivityActionType
- url: Annotated[str, Field(strict=True)] = Field(description="HTTPS URL. For open_url it is opened in browser. For webhook it is called by ActivitySmith backend.")
+ url: StrictStr = Field(description="Action URL. For open_url, use an HTTPS or shortcuts:// URL. For webhook, use an HTTPS URL called by the ActivitySmith backend.")
method: Optional[LiveActivityWebhookMethod] = Field(default=LiveActivityWebhookMethod.POST, description="Webhook HTTP method. Used only when type=webhook.")
body: Optional[Dict[str, Any]] = Field(default=None, description="Optional webhook payload body. Used only when type=webhook.")
additional_properties: Dict[str, Any] = {}
- __properties: ClassVar[List[str]] = ["title", "type", "url", "method", "body"]
-
- @field_validator('url')
- def url_validate_regular_expression(cls, value):
- """Validates the regular expression"""
- if not re.match(r"^https:\/\/", value):
- raise ValueError(r"must validate the regular expression /^https:\/\//")
- return value
+ __properties: ClassVar[List[str]] = []
model_config = ConfigDict(
populate_by_name=True,
@@ -50,6 +42,14 @@ def url_validate_regular_expression(cls, value):
protected_namespaces=(),
)
+ @model_validator(mode="after")
+ def validate_url_for_type(self) -> Self:
+ if self.type == LiveActivityActionType.OPEN_URL and not (self.url.startswith("https://") or self.url.startswith("shortcuts://")):
+ raise ValueError("open_url action url must use https or shortcuts")
+ if self.type == LiveActivityActionType.WEBHOOK and not self.url.startswith("https://"):
+ raise ValueError("webhook action url must use https")
+ return self
+
def to_str(self) -> str:
"""Returns the string representation of the model using alias"""
@@ -102,11 +102,6 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
return cls.model_validate(obj)
_obj = cls.model_validate({
- "title": obj.get("title"),
- "type": obj.get("type"),
- "url": obj.get("url"),
- "method": obj.get("method") if obj.get("method") is not None else LiveActivityWebhookMethod.POST,
- "body": obj.get("body")
})
# store additional fields in additional_properties
for _key in obj.keys():
@@ -115,4 +110,3 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
return _obj
-
diff --git a/activitysmith_openapi/models/live_activity_alert_badge.py b/activitysmith_openapi/models/live_activity_alert_badge.py
index c499df7..e4e4d0a 100644
--- a/activitysmith_openapi/models/live_activity_alert_badge.py
+++ b/activitysmith_openapi/models/live_activity_alert_badge.py
@@ -26,7 +26,7 @@
class LiveActivityAlertBadge(BaseModel):
"""
- Optional badge for Alert Live Activities.
+ Optional badge for Live Activities.
""" # noqa: E501
title: Annotated[str, Field(min_length=1, strict=True)]
color: Optional[LiveActivityColor] = Field(default=None, description="Optional badge color.")
diff --git a/activitysmith_openapi/models/live_activity_alert_icon.py b/activitysmith_openapi/models/live_activity_alert_icon.py
index 06a1ed2..1f46b7c 100644
--- a/activitysmith_openapi/models/live_activity_alert_icon.py
+++ b/activitysmith_openapi/models/live_activity_alert_icon.py
@@ -26,7 +26,7 @@
class LiveActivityAlertIcon(BaseModel):
"""
- Optional SF Symbol icon for Alert Live Activities.
+ Optional SF Symbol icon for Live Activities.
""" # noqa: E501
symbol: Annotated[str, Field(min_length=1, strict=True)] = Field(description="Apple SF Symbol name.")
color: Optional[LiveActivityColor] = Field(default=None, description="Optional icon color.")
diff --git a/activitysmith_openapi/models/push_notification_action.py b/activitysmith_openapi/models/push_notification_action.py
index 8a09f6b..8822862 100644
--- a/activitysmith_openapi/models/push_notification_action.py
+++ b/activitysmith_openapi/models/push_notification_action.py
@@ -17,9 +17,8 @@
import re # noqa: F401
import json
-from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator
+from pydantic import BaseModel, ConfigDict, Field, StrictStr, model_validator
from typing import Any, ClassVar, Dict, List, Optional
-from typing_extensions import Annotated
from activitysmith_openapi.models.push_notification_action_type import PushNotificationActionType
from activitysmith_openapi.models.push_notification_webhook_method import PushNotificationWebhookMethod
from typing import Optional, Set
@@ -31,18 +30,11 @@ class PushNotificationAction(BaseModel):
""" # noqa: E501
title: StrictStr = Field(description="Button title displayed in iOS expanded notification UI.")
type: PushNotificationActionType
- url: Annotated[str, Field(strict=True)] = Field(description="HTTPS URL. For open_url it is opened in browser. For webhook it is called by ActivitySmith backend.")
+ url: StrictStr = Field(description="Action URL. For open_url, use an HTTPS or shortcuts:// URL. For webhook, use an HTTPS URL called by the ActivitySmith backend.")
method: Optional[PushNotificationWebhookMethod] = Field(default=PushNotificationWebhookMethod.POST, description="Webhook HTTP method. Used only when type=webhook.")
body: Optional[Dict[str, Any]] = Field(default=None, description="Optional webhook payload body. Used only when type=webhook.")
additional_properties: Dict[str, Any] = {}
- __properties: ClassVar[List[str]] = ["title", "type", "url", "method", "body"]
-
- @field_validator('url')
- def url_validate_regular_expression(cls, value):
- """Validates the regular expression"""
- if not re.match(r"^https:\/\/", value):
- raise ValueError(r"must validate the regular expression /^https:\/\//")
- return value
+ __properties: ClassVar[List[str]] = []
model_config = ConfigDict(
populate_by_name=True,
@@ -50,6 +42,14 @@ def url_validate_regular_expression(cls, value):
protected_namespaces=(),
)
+ @model_validator(mode="after")
+ def validate_url_for_type(self) -> Self:
+ if self.type == PushNotificationActionType.OPEN_URL and not (self.url.startswith("https://") or self.url.startswith("shortcuts://")):
+ raise ValueError("open_url action url must use https or shortcuts")
+ if self.type == PushNotificationActionType.WEBHOOK and not self.url.startswith("https://"):
+ raise ValueError("webhook action url must use https")
+ return self
+
def to_str(self) -> str:
"""Returns the string representation of the model using alias"""
@@ -102,11 +102,6 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
return cls.model_validate(obj)
_obj = cls.model_validate({
- "title": obj.get("title"),
- "type": obj.get("type"),
- "url": obj.get("url"),
- "method": obj.get("method") if obj.get("method") is not None else PushNotificationWebhookMethod.POST,
- "body": obj.get("body")
})
# store additional fields in additional_properties
for _key in obj.keys():
@@ -115,4 +110,3 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
return _obj
-
diff --git a/activitysmith_openapi/models/push_notification_request.py b/activitysmith_openapi/models/push_notification_request.py
index 78a0f1d..a056f4d 100644
--- a/activitysmith_openapi/models/push_notification_request.py
+++ b/activitysmith_openapi/models/push_notification_request.py
@@ -33,7 +33,7 @@ class PushNotificationRequest(BaseModel):
message: Optional[StrictStr] = None
subtitle: Optional[StrictStr] = None
media: Optional[Annotated[str, Field(strict=True)]] = Field(default=None, description="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`.")
- redirection: Optional[Annotated[str, Field(strict=True)]] = Field(default=None, description="Optional HTTPS URL opened when user taps the notification body. Overrides the default tap target from `media` when both are provided.")
+ redirection: Optional[Annotated[str, Field(strict=True)]] = Field(default=None, description="Optional HTTPS or shortcuts:// URL opened when user taps the notification body. Overrides the default tap target from `media` when both are provided.")
actions: Optional[Annotated[List[PushNotificationAction], Field(max_length=4)]] = Field(default=None, description="Optional interactive actions shown when users expand the notification. Cannot be combined with `media`.")
payload: Optional[Dict[str, Any]] = None
badge: Optional[StrictInt] = None
@@ -58,8 +58,8 @@ def redirection_validate_regular_expression(cls, value):
if value is None:
return value
- if not re.match(r"^https:\/\/", value):
- raise ValueError(r"must validate the regular expression /^https:\/\//")
+ if not re.match(r"^(https|shortcuts):\/\/", value):
+ raise ValueError(r"must validate the regular expression /^(https|shortcuts):\/\//")
return value
model_config = ConfigDict(
diff --git a/activitysmith_openapi/models/stream_content_state.py b/activitysmith_openapi/models/stream_content_state.py
index 7c0e0ab..c07f8ad 100644
--- a/activitysmith_openapi/models/stream_content_state.py
+++ b/activitysmith_openapi/models/stream_content_state.py
@@ -43,8 +43,8 @@ class StreamContentState(BaseModel):
step_colors: Optional[List[StrictStr]] = Field(default=None, description="Optional. Colors for completed steps. When used with segmented_progress, the array length should match current_step.")
metrics: Optional[Annotated[List[ActivityMetric], Field(min_length=1, max_length=8)]] = Field(default=None, description="Use for metrics and stats activities.")
message: Optional[Annotated[str, Field(min_length=1, strict=True)]] = Field(default=None, description="Required for type=alert.")
- icon: Optional[LiveActivityAlertIcon] = Field(default=None, description="Optional SF Symbol icon for type=alert.")
- badge: Optional[LiveActivityAlertBadge] = Field(default=None, description="Optional badge for type=alert.")
+ icon: Optional[LiveActivityAlertIcon] = Field(default=None, description="Optional SF Symbol icon. Supported by alert, progress, segmented_progress, metrics, and stats.")
+ badge: Optional[LiveActivityAlertBadge] = Field(default=None, description="Optional badge. Supported by alert, progress, and segmented_progress.")
auto_dismiss_seconds: Optional[Annotated[int, Field(strict=True, ge=0)]] = Field(default=None, description="Optional. Seconds before the ended Live Activity is dismissed.")
auto_dismiss_minutes: Optional[Annotated[int, Field(strict=True, ge=0)]] = Field(default=None, description="Optional. Minutes before the ended Live Activity is dismissed.")
additional_properties: Dict[str, Any] = {}
diff --git a/activitysmith_openapi/test/test_live_activity_action.py b/activitysmith_openapi/test/test_live_activity_action.py
index 731ebee..e88a849 100644
--- a/activitysmith_openapi/test/test_live_activity_action.py
+++ b/activitysmith_openapi/test/test_live_activity_action.py
@@ -15,6 +15,7 @@
import unittest
from activitysmith_openapi.models.live_activity_action import LiveActivityAction
+from activitysmith_openapi.models.live_activity_action_type import LiveActivityActionType
class TestLiveActivityAction(unittest.TestCase):
"""LiveActivityAction unit test stubs"""
@@ -37,7 +38,7 @@ def make_instance(self, include_optional) -> LiveActivityAction:
return LiveActivityAction(
title = '',
type = 'open_url',
- url = 'https:/',
+ url = '',
method = 'POST',
body = { }
)
@@ -45,7 +46,7 @@ def make_instance(self, include_optional) -> LiveActivityAction:
return LiveActivityAction(
title = '',
type = 'open_url',
- url = 'https:/',
+ url = '',
)
"""
@@ -54,5 +55,22 @@ def testLiveActivityAction(self):
# inst_req_only = self.make_instance(include_optional=False)
# inst_req_and_optional = self.make_instance(include_optional=True)
+ def test_open_url_allows_shortcuts_url(self):
+ action = LiveActivityAction(
+ title="Chat",
+ type=LiveActivityActionType.OPEN_URL,
+ url="shortcuts://run-shortcut?name=JARVIS",
+ )
+
+ self.assertEqual("shortcuts://run-shortcut?name=JARVIS", action.url)
+
+ def test_webhook_rejects_shortcuts_url(self):
+ with self.assertRaises(ValueError):
+ LiveActivityAction(
+ title="Chat",
+ type=LiveActivityActionType.WEBHOOK,
+ url="shortcuts://run-shortcut?name=JARVIS",
+ )
+
if __name__ == '__main__':
unittest.main()
diff --git a/activitysmith_openapi/test/test_push_notification_action.py b/activitysmith_openapi/test/test_push_notification_action.py
index 7f29c03..e670103 100644
--- a/activitysmith_openapi/test/test_push_notification_action.py
+++ b/activitysmith_openapi/test/test_push_notification_action.py
@@ -15,6 +15,7 @@
import unittest
from activitysmith_openapi.models.push_notification_action import PushNotificationAction
+from activitysmith_openapi.models.push_notification_action_type import PushNotificationActionType
class TestPushNotificationAction(unittest.TestCase):
"""PushNotificationAction unit test stubs"""
@@ -37,7 +38,7 @@ def make_instance(self, include_optional) -> PushNotificationAction:
return PushNotificationAction(
title = '',
type = 'open_url',
- url = 'https:/',
+ url = '',
method = 'POST',
body = { }
)
@@ -45,7 +46,7 @@ def make_instance(self, include_optional) -> PushNotificationAction:
return PushNotificationAction(
title = '',
type = 'open_url',
- url = 'https:/',
+ url = '',
)
"""
@@ -54,5 +55,22 @@ def testPushNotificationAction(self):
# inst_req_only = self.make_instance(include_optional=False)
# inst_req_and_optional = self.make_instance(include_optional=True)
+ def test_open_url_allows_shortcuts_url(self):
+ action = PushNotificationAction(
+ title="Chat",
+ type=PushNotificationActionType.OPEN_URL,
+ url="shortcuts://run-shortcut?name=JARVIS",
+ )
+
+ self.assertEqual("shortcuts://run-shortcut?name=JARVIS", action.url)
+
+ def test_webhook_rejects_shortcuts_url(self):
+ with self.assertRaises(ValueError):
+ PushNotificationAction(
+ title="Chat",
+ type=PushNotificationActionType.WEBHOOK,
+ url="shortcuts://run-shortcut?name=JARVIS",
+ )
+
if __name__ == '__main__':
unittest.main()
diff --git a/activitysmith_openapi/test/test_push_notification_request.py b/activitysmith_openapi/test/test_push_notification_request.py
index 7c7e961..e339292 100644
--- a/activitysmith_openapi/test/test_push_notification_request.py
+++ b/activitysmith_openapi/test/test_push_notification_request.py
@@ -39,7 +39,7 @@ def make_instance(self, include_optional) -> PushNotificationRequest:
message = '',
subtitle = '',
media = 'https:/',
- redirection = 'https:/',
+ redirection = 'shortcuts:/',
actions = [
{
'key' : null
diff --git a/tests/test_resources.py b/tests/test_resources.py
index 8db8a4f..6d87606 100644
--- a/tests/test_resources.py
+++ b/tests/test_resources.py
@@ -119,7 +119,7 @@ def test_push_action_helper(monkeypatch):
action(
title="Open CRM Profile",
type="open_url",
- url="https://crm.example.com/customers/cus_9f3a1d",
+ url="shortcuts://run-shortcut?name=Open%20CRM",
)
],
)
@@ -132,7 +132,7 @@ def test_push_action_helper(monkeypatch):
{
"title": "Open CRM Profile",
"type": "open_url",
- "url": "https://crm.example.com/customers/cus_9f3a1d",
+ "url": "shortcuts://run-shortcut?name=Open%20CRM",
}
],
}
@@ -170,9 +170,19 @@ def test_notifications_preserve_media_and_redirection(monkeypatch):
}
client.notifications.send(payload)
+ client.notifications.send(
+ title="Run Shortcut",
+ redirection="shortcuts://run-shortcut?name=Jarvis",
+ )
assert client.notifications._api.calls == [
{"push_notification_request": payload},
+ {
+ "push_notification_request": {
+ "title": "Run Shortcut",
+ "redirection": "shortcuts://run-shortcut?name=Jarvis",
+ }
+ },
]
@@ -383,6 +393,68 @@ def test_live_activities_support_alert_helpers(monkeypatch):
]
+def test_live_activities_support_icon_and_badge_on_non_alert_types(monkeypatch):
+ monkeypatch.setattr(client_module, "PushNotificationsApi", FakePushNotificationsApi)
+ monkeypatch.setattr(client_module, "LiveActivitiesApi", FakeLiveActivitiesApi)
+ monkeypatch.setattr(client_module, "MetricsApi", FakeMetricsApi)
+
+ client = ActivitySmith(api_key="x")
+
+ client.live_activities.stream(
+ "prod-web-1",
+ content_state=content_state(
+ title="Server Health",
+ subtitle="prod-web-1",
+ type=client.live_activities.TYPE_METRICS,
+ icon=alert_icon("server.rack", color="blue"),
+ metrics=[metric(label="CPU", value=18, unit="%")],
+ ),
+ )
+ client.live_activities.stream(
+ "nightly-database-backup",
+ content_state=content_state(
+ title="Nightly Database Backup",
+ subtitle="verify restore",
+ type=client.live_activities.TYPE_PROGRESS,
+ badge=alert_badge("S3", color="cyan"),
+ percentage=62,
+ ),
+ )
+
+ assert client.live_activities._api.calls == [
+ (
+ "stream",
+ {
+ "stream_key": "prod-web-1",
+ "live_activity_stream_request": {
+ "content_state": {
+ "title": "Server Health",
+ "subtitle": "prod-web-1",
+ "type": client.live_activities.TYPE_METRICS,
+ "icon": {"symbol": "server.rack", "color": "blue"},
+ "metrics": [{"label": "CPU", "value": 18, "unit": "%"}],
+ },
+ },
+ },
+ ),
+ (
+ "stream",
+ {
+ "stream_key": "nightly-database-backup",
+ "live_activity_stream_request": {
+ "content_state": {
+ "title": "Nightly Database Backup",
+ "subtitle": "verify restore",
+ "type": client.live_activities.TYPE_PROGRESS,
+ "badge": {"title": "S3", "color": "cyan"},
+ "percentage": 62,
+ },
+ },
+ },
+ ),
+ ]
+
+
def test_live_activities_build_requests_from_named_fields(monkeypatch):
monkeypatch.setattr(client_module, "PushNotificationsApi", FakePushNotificationsApi)
monkeypatch.setattr(client_module, "LiveActivitiesApi", FakeLiveActivitiesApi)
@@ -396,7 +468,7 @@ def test_live_activities_build_requests_from_named_fields(monkeypatch):
action_payload = action(
title="Open Dashboard",
type="open_url",
- url="https://ops.example.com/servers/prod-web-1",
+ url="shortcuts://run-shortcut?name=Open%20Dashboard",
)
state_payload = content_state(
title="Server Health",
@@ -563,7 +635,7 @@ def test_live_activities_pass_action_payloads_through(monkeypatch):
"action": {
"title": "Open Workflow",
"type": "open_url",
- "url": "https://github.com/acme/payments-api/actions/runs/1234567890",
+ "url": "shortcuts://run-shortcut?name=Deploy%20Status",
},
}
@@ -595,7 +667,7 @@ def test_live_activities_pass_action_payloads_through(monkeypatch):
"action": {
"title": "Open Workflow",
"type": "open_url",
- "url": "https://github.com/acme/payments-api/actions/runs/1234567890",
+ "url": "shortcuts://run-shortcut?name=Deploy%20Status",
},
}