More SDK comments (#2796)

* sdk tweaks

* switch back to deeppartial

* WIP, update comments

* reinstall chesterton's fence

* more comments

* delete extra package.lock

* handle TODOs

---------

Co-authored-by: Aiden McClelland <me@drbonez.dev>
This commit is contained in:
Matt Hill
2024-12-02 13:58:28 -07:00
committed by GitHub
parent 22a32af750
commit 7a96e94491
10 changed files with 139 additions and 11 deletions

View File

@@ -124,15 +124,20 @@ impl fmt::Display for ActionResultV0 {
#[derive(Debug, Serialize, Deserialize, TS)]
#[serde(rename_all = "camelCase")]
pub struct ActionResultV1 {
/// Primary text to display as the header of the response modal. e.g. "Success!", "Name Updated", or "Service Information", whatever makes sense
pub title: String,
/// (optional) A general message for the user, just under the title
pub message: Option<String>,
/// (optional) Structured data to present inside the modal
pub result: Option<ActionResultValue>,
}
#[derive(Debug, Serialize, Deserialize, TS)]
#[serde(rename_all = "camelCase")]
pub struct ActionResultMember {
/// A human-readable name or title of the value, such as "Last Active" or "Login Password"
pub name: String,
/// (optional) A description of the value, such as an explaining why it exists or how to use it
pub description: Option<String>,
#[serde(flatten)]
#[ts(flatten)]
@@ -145,12 +150,17 @@ pub struct ActionResultMember {
#[serde(tag = "type")]
pub enum ActionResultValue {
Single {
/// The actual string value to display
value: String,
/// Whether or not to include a copy to clipboard icon to copy the value
copyable: bool,
/// Whether or not to also display the value as a QR code
qr: bool,
/// Whether or not to mask the value using ●●●●●●●, which is useful for password or other sensitive information
masked: bool,
},
Group {
/// An new group of nested values, experienced by the user as an accordion dropdown
value: Vec<ActionResultMember>,
},
}

View File

@@ -322,13 +322,25 @@ pub enum AllowedStatuses {
#[serde(rename_all = "camelCase")]
#[model = "Model<Self>"]
pub struct ActionMetadata {
/// A human-readable name
pub name: String,
/// A detailed description of what the action will do
pub description: String,
/// Presents as an alert prior to executing the action. Should be used sparingly but important if the action could have harmful, unintended consequences
pub warning: Option<String>,
#[serde(default)]
/// One of: "enabled", "hidden", or { disabled: "" }
/// - "enabled" - the action is available be run
/// - "hidden" - the action cannot be seen or run
/// - { disabled: "example explanation" } means the action is visible but cannot be run. Replace "example explanation" with a reason why the action is disable to prevent user confusion.
pub visibility: ActionVisibility,
/// One of: "only-stopped", "only-running", "all"
/// - "only-stopped" - the action can only be run when the service is stopped
/// - "only-running" - the action can only be run when the service is running
/// - "any" - the action can only be run regardless of the service's status
pub allowed_statuses: AllowedStatuses,
pub has_input: bool,
/// If provided, this action will be nested under a header of this value, along with other actions of the same group
pub group: Option<String>,
}

View File

@@ -3,11 +3,35 @@ import type { ActionVisibility } from "./ActionVisibility"
import type { AllowedStatuses } from "./AllowedStatuses"
export type ActionMetadata = {
/**
* A human-readable name
*/
name: string
/**
* A detailed description of what the action will do
*/
description: string
/**
* Presents as an alert prior to executing the action. Should be used sparingly but important if the action could have harmful, unintended consequences
*/
warning: string | null
/**
* One of: "enabled", "hidden", or { disabled: "" }
* - "enabled" - the action is available be run
* - "hidden" - the action cannot be seen or run
* - { disabled: "example explanation" } means the action is visible but cannot be run. Replace "example explanation" with a reason why the action is disable to prevent user confusion.
*/
visibility: ActionVisibility
/**
* One of: "only-stopped", "only-running", "all"
* - "only-stopped" - the action can only be run when the service is stopped
* - "only-running" - the action can only be run when the service is running
* - "any" - the action can only be run regardless of the service's status
*/
allowedStatuses: AllowedStatuses
hasInput: boolean
/**
* If provided, this action will be nested under a header of this value, along with other actions of the same group
*/
group: string | null
}

View File

@@ -1,15 +1,39 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type ActionResultMember = {
/**
* A human-readable name or title of the value, such as "Last Active" or "Login Password"
*/
name: string
/**
* (optional) A description of the value, such as an explaining why it exists or how to use it
*/
description: string | null
} & (
| {
type: "single"
/**
* The actual string value to display
*/
value: string
/**
* Whether or not to include a copy to clipboard icon to copy the value
*/
copyable: boolean
/**
* Whether or not to also display the value as a QR code
*/
qr: boolean
/**
* Whether or not to mask the value using ●●●●●●●, which is useful for password or other sensitive information
*/
masked: boolean
}
| { type: "group"; value: Array<ActionResultMember> }
| {
type: "group"
/**
* An new group of nested values, experienced by the user as an accordion dropdown
*/
value: Array<ActionResultMember>
}
)

View File

@@ -2,7 +2,16 @@
import type { ActionResultValue } from "./ActionResultValue"
export type ActionResultV1 = {
/**
* Primary text to display as the header of the response modal. e.g. "Success!", "Name Updated", or "Service Information", whatever makes sense
*/
title: string
/**
* (optional) A general message for the user, just under the title
*/
message: string | null
/**
* (optional) Structured data to present inside the modal
*/
result: ActionResultValue | null
}

View File

@@ -4,9 +4,27 @@ import type { ActionResultMember } from "./ActionResultMember"
export type ActionResultValue =
| {
type: "single"
/**
* The actual string value to display
*/
value: string
/**
* Whether or not to include a copy to clipboard icon to copy the value
*/
copyable: boolean
/**
* Whether or not to also display the value as a QR code
*/
qr: boolean
/**
* Whether or not to mask the value using ●●●●●●●, which is useful for password or other sensitive information
*/
masked: boolean
}
| { type: "group"; value: Array<ActionResultMember> }
| {
type: "group"
/**
* An new group of nested values, experienced by the user as an accordion dropdown
*/
value: Array<ActionResultMember>
}

6
sdk/package-lock.json generated
View File

@@ -1,6 +0,0 @@
{
"name": "sdk",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}

View File

@@ -19,7 +19,22 @@ import { CommandController } from "./CommandController"
export const cpExec = promisify(CP.exec)
export const cpExecFile = promisify(CP.execFile)
export type Ready = {
/** A human-readable display name for the health check. If null, the health check itself will be from the UI */
display: string | null
/**
* @description The function to determine the health status of the daemon
*
* The SDK provides some built-in health checks. To see them, type sdk.healthCheck.
*
* @example
* ```
fn: () =>
sdk.healthCheck.checkPortListening(effects, 80, {
successMessage: 'service listening on port 80',
errorMessage: 'service is unreachable',
})
* ```
*/
fn: (
spawnable: ExecSpawnable,
) => Promise<HealthCheckResult> | HealthCheckResult
@@ -32,11 +47,23 @@ type DaemonsParams<
Command extends string,
Id extends string,
> = {
/** The command line command to start the daemon */
command: T.CommandType
image: { id: keyof Manifest["images"] & T.ImageId; sharedRun?: boolean }
/** Information about the image in which the daemon runs */
image: {
/** The ID of the image. Must be one of the image IDs declared in the manifest */
id: keyof Manifest["images"] & T.ImageId
/**
* Whether or not to share the `/run` directory with the parent container.
* This is useful if you are trying to connect to a service that exposes a unix domain socket or auth cookie via the `/run` directory
*/
sharedRun?: boolean
}
/** For mounting the necessary volumes. Syntax: sdk.Mounts.of().addVolume() */
mounts: Mounts<Manifest>
env?: Record<string, string>
ready: Ready
/** An array of IDs of prior daemons whose successful initializations are required before this daemon will initialize */
requires: Exclude<Ids, Id>[]
sigtermTimeout?: number
onStdout?: (chunk: Buffer | string | any) => void

View File

@@ -30,9 +30,13 @@ export class Mounts<Manifest extends T.SDKManifest> {
}
addVolume(
/** The ID of the volume to mount. Must be one of the volume IDs defined in the manifest */
id: Manifest["volumes"][number],
/** The path within the volume to mount. Use `null` to mount the entire volume */
subpath: string | null,
/** Where to mount the volume. e.g. /data */
mountpoint: string,
/** Whether or not the volume should be readonly for this daemon */
readonly: boolean,
) {
this.volumes.push({
@@ -45,8 +49,11 @@ export class Mounts<Manifest extends T.SDKManifest> {
}
addAssets(
/** The ID of the asset directory to mount. This is typically the same as the folder name in your assets directory */
id: Manifest["assets"][number],
/** The path within the asset directory to mount. Use `null` to mount the entire volume */
subpath: string | null,
/** Where to mount the asset. e.g. /asset */
mountpoint: string,
) {
this.assets.push({
@@ -58,10 +65,15 @@ export class Mounts<Manifest extends T.SDKManifest> {
}
addDependency<DependencyManifest extends T.SDKManifest>(
/** The ID of the dependency service */
dependencyId: keyof Manifest["dependencies"] & string,
/** The ID of the volume belonging to the dependency service to mount */
volumeId: DependencyManifest["volumes"][number],
/** The path within the dependency's volume to mount. Use `null` to mount the entire volume */
subpath: string | null,
/** Where to mount the dependency's volume. e.g. /service-id */
mountpoint: string,
/** Whether or not the volume should be readonly for this daemon */
readonly: boolean,
) {
this.dependencies.push({

View File

@@ -6,8 +6,6 @@ import { Variants } from "../../../base/lib/actions/input/builder/variants"
import { ValueSpec } from "../../../base/lib/actions/input/inputSpecTypes"
import { setupManifest } from "../manifest/setupManifest"
import { StartSdk } from "../StartSdk"
import { VersionGraph } from "../version/VersionGraph"
import { VersionInfo } from "../version/VersionInfo"
describe("builder tests", () => {
test("text", async () => {