mirror of
https://github.com/HeyPuter/puter.git
synced 2026-10-11 06:11:56 +00:00
improve teams docs (#4025)
This commit is contained in:
1 parent
42b204f46e
commit
384524a027
9 files changed
+232
-203
No files matched your search
@@ -23,6 +23,8 @@ Various object types and classes that represent different entities in the Puter
|
||||
- **[PuterPeerServer](/Objects/puterpeerserver/)** - Represents a peer server and its connected clients
|
||||
- **[Speech2TxtResult](/Objects/speech2txtresult/)** - Represents speech-to-text transcription results
|
||||
- **[Subdomain](/Objects/subdomain/)** - Represents a subdomain
|
||||
- **[Team](/Objects/team/)** - Represents a Puter team
|
||||
- **[TeamDirectoryEntry](/Objects/teamdirectoryentry/)** - Represents a member of a team
|
||||
- **[TTSEngine](/Objects/ttsengine/)** - Represents an available text-to-speech engine/model
|
||||
- **[TTSVoice](/Objects/ttsvoice/)** - Represents an available text-to-speech voice
|
||||
- **[ToolCall](/Objects/toolcall/)** - Represents a tool invocation request
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
title: Team
|
||||
description: The Team object containing information about a Puter team.
|
||||
---
|
||||
|
||||
The `Team` object contains information about a Puter team, returned by [`puter.teams.list()`](/Teams/list/).
|
||||
|
||||
## Attributes
|
||||
|
||||
#### `uid` (String)
|
||||
|
||||
The team's unique identifier. Pass this to [`puter.teams.listDirectory()`](/Teams/listDirectory/).
|
||||
|
||||
#### `name` (String)
|
||||
|
||||
The team's display name, or `null` if it has none.
|
||||
|
||||
#### `handle` (String)
|
||||
|
||||
The team's short handle, or `null` if it has none. The handle can change, so store the `uid` instead.
|
||||
|
||||
#### `isOwner` (Boolean)
|
||||
|
||||
Whether the current user is the team owner.
|
||||
|
||||
#### `directoryEnabled` (Boolean)
|
||||
|
||||
Whether the team owner has enabled the directory setting, which lets apps use the Teams API for this team.
|
||||
|
||||
#### `createdAt` (String)
|
||||
|
||||
When the team was created, in `YYYY-MM-DDTHH:MM:SSZ` format.
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
title: TeamDirectoryEntry
|
||||
description: The TeamDirectoryEntry object containing information about a team member.
|
||||
---
|
||||
|
||||
The `TeamDirectoryEntry` object contains information about a team member, returned by [`puter.teams.listDirectory()`](/Teams/listDirectory/).
|
||||
|
||||
## Attributes
|
||||
|
||||
#### `username` (String)
|
||||
|
||||
The member's Puter username.
|
||||
|
||||
#### `uuid` (String)
|
||||
|
||||
The member's unique account identifier. Unlike the username, it never changes.
|
||||
+90
-88
@@ -1,109 +1,111 @@
|
||||
---
|
||||
title: Teams
|
||||
description: Detect team context and look up a user's colleagues with the Teams API
|
||||
description: Get the user's team and list its members with the Puter.js Teams API
|
||||
platforms: [websites, apps, nodejs, workers]
|
||||
---
|
||||
|
||||
<div class="info">The Teams API is in beta. Method shapes, limits, and behavior may change between releases.</div>
|
||||
|
||||
The Puter.js Teams feature lets your app see the team context around the user in front of it: whether they belong to one, and who their colleagues are.
|
||||
The Teams API lets your app interact with the Puter Teams feature.
|
||||
|
||||
A team is a Puter account that pays for other accounts. Members are ordinary Puter accounts — your app talks to them like any other user, and the team never gains access to a member's files. Team *administration* (creating teams, provisioning accounts, suspending them) happens in the account console rather than through apps, so what `puter.teams` offers is read-only.
|
||||
Puter Teams lets an organization bring its members together. Any user can create a team and invite members. Each member keeps their own Puter account, but belongs to the team, so the owner can manage them and cover their paid plan in one place.
|
||||
|
||||
With this API, your app can get the team the user currently belongs to and list the members of that team. To use the Teams API, the team owner must enable the directory setting in the [Teams dashboard](https://puter.com/#teams).
|
||||
|
||||
## Features
|
||||
|
||||
**Team context.** `list()` tells you whether the signed-in user belongs to a team, and is also how you detect whether the deployment has Teams at all: it rejects with `not_found` where the feature is off, and resolves to an empty array where it is on and the user has no team. Called from an app, it only includes teams whose owner opened the directory to apps (see below); others are simply omitted.
|
||||
<div style="overflow:hidden; margin-bottom: 30px;">
|
||||
<div class="example-group active" data-section="list"><span>Get Team</span></div>
|
||||
<div class="example-group" data-section="list-directory"><span>List Members</span></div>
|
||||
</div>
|
||||
|
||||
**Member and colleague lookup.** `listDirectory()` returns the team's active members so your app can suggest people by name instead of asking users to type usernames. It is opt-in per team: until an owner opens the directory to apps, an app gets `team_not_found`, which is indistinguishable from having no team.
|
||||
<div class="example-content" data-section="list" style="display:block;">
|
||||
|
||||
**Sharing with a team.** Anything shared with a team reaches every member with one grant, including anyone added later. Pass the team's `uid` as the recipient of [`puter.fs.share()`](/FS/share/); there is no string form, since a bare string is always read as an email or username.
|
||||
#### Get the current user's team information
|
||||
|
||||
**Stable identifiers.** A team has a `uid` and an optional `handle`. Only the `uid` is stable — a handle is a mutable label, and deleting the team releases it for anyone else to take. Display the `name` and `handle`; pass the `uid`.
|
||||
```html;teams-list
|
||||
<html>
|
||||
<body>
|
||||
<script src="https://js.puter.com/v2/"></script>
|
||||
<script>
|
||||
(async () => {
|
||||
const teams = await puter.teams.list();
|
||||
|
||||
if (teams.length === 0) {
|
||||
puter.print('You are not on a team.');
|
||||
return;
|
||||
}
|
||||
|
||||
for (const team of teams) {
|
||||
puter.print(`${team.name ?? team.handle ?? 'Unnamed team'}<br>`);
|
||||
puter.print(`uid: ${team.uid}<br>`);
|
||||
puter.print(`owner: ${team.isOwner}<br>`);
|
||||
puter.print(`directory open to apps: ${team.directoryEnabled}<br><br>`);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
<div class="example-content" data-section="list-directory">
|
||||
|
||||
#### List the members of the user's team
|
||||
|
||||
```html;teams-directory
|
||||
<html>
|
||||
<body>
|
||||
<script src="https://js.puter.com/v2/"></script>
|
||||
<select id="colleagues"><option>Loading…</option></select>
|
||||
<button id="pick">Pick</button>
|
||||
<script>
|
||||
const select = document.getElementById('colleagues');
|
||||
|
||||
(async () => {
|
||||
const [team] = await puter.teams.list();
|
||||
if (!team) {
|
||||
select.innerHTML = '<option>You are not on a team</option>';
|
||||
return;
|
||||
}
|
||||
|
||||
// Off by default, and the usual reason the list comes back empty.
|
||||
if (!team.directoryEnabled) {
|
||||
select.innerHTML = '<option>Directory is closed to apps</option>';
|
||||
return;
|
||||
}
|
||||
|
||||
const entries = await puter.teams.listDirectory(team.uid);
|
||||
select.innerHTML = '';
|
||||
for (const { username, uuid } of entries) {
|
||||
const option = document.createElement('option');
|
||||
// Store the uuid: it survives a username change.
|
||||
option.value = uuid;
|
||||
option.textContent = username;
|
||||
select.append(option);
|
||||
}
|
||||
})();
|
||||
|
||||
document.getElementById('pick').addEventListener('click', () => {
|
||||
const option = select.selectedOptions[0];
|
||||
if (option) puter.print(`${option.textContent} → ${option.value}<br>`);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## Functions
|
||||
|
||||
- **[`puter.teams.list()`](/Teams/list/)** - List the teams the signed-in user belongs to, and detect whether Teams is available at all
|
||||
- **[`puter.teams.listDirectory()`](/Teams/listDirectory/)** - List a team's members, where the owner has opened the directory to apps
|
||||
|
||||
Both are keyset-paginated and take the same options; see each method page for the paging forms and the full error list.
|
||||
- **[`puter.teams.list()`](/Teams/list/)** - Get the current user's team information
|
||||
- **[`puter.teams.listDirectory()`](/Teams/listDirectory/)** - List the members of a team
|
||||
|
||||
## Examples
|
||||
|
||||
<strong class="example-title">Detect whether the user is on a team</strong>
|
||||
You can see various Puter.js Teams features in action from the following examples:
|
||||
|
||||
```html
|
||||
<html>
|
||||
<body>
|
||||
<script src="https://js.puter.com/v2/"></script>
|
||||
<script>
|
||||
(async () => {
|
||||
let teams = [];
|
||||
try {
|
||||
teams = await puter.teams.list();
|
||||
} catch (e) {
|
||||
// Teams are unavailable on this deployment.
|
||||
}
|
||||
puter.print(teams.length
|
||||
? `On ${teams.length} team(s): ${teams.map(t => t.name).join(', ')}`
|
||||
: 'Not on a team');
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
<strong class="example-title">Suggest a colleague to share with</strong>
|
||||
|
||||
```html
|
||||
<html>
|
||||
<body>
|
||||
<script src="https://js.puter.com/v2/"></script>
|
||||
<script>
|
||||
(async () => {
|
||||
const [team] = await puter.teams.list();
|
||||
if ( ! team ) return puter.print('Not on a team');
|
||||
|
||||
try {
|
||||
const colleagues = await puter.teams.listDirectory(team.uid);
|
||||
colleagues.forEach(c => puter.print(`${c.username}<br>`));
|
||||
} catch (e) {
|
||||
// The owner has not opened the directory to apps.
|
||||
puter.print('No directory for this team');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
<strong class="example-title">Share a file with the whole team</strong>
|
||||
|
||||
```html
|
||||
<html>
|
||||
<body>
|
||||
<script src="https://js.puter.com/v2/"></script>
|
||||
<script>
|
||||
(async () => {
|
||||
const [team] = await puter.teams.list();
|
||||
await puter.fs.write('report.txt', 'Quarterly numbers');
|
||||
await puter.fs.share({
|
||||
path: 'report.txt',
|
||||
recipient: { team: team.uid },
|
||||
mode: 'read',
|
||||
});
|
||||
puter.print(`Shared with everyone on ${team.name}`);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## What is deliberately absent
|
||||
|
||||
- **No sharing-policy controls.** A team cannot restrict who its members share
|
||||
with: there is no external-sharing policy, no domain allowlist, and no control
|
||||
over public links. A member shares exactly as any other Puter user does, with
|
||||
anyone. This is the assumption most teams bring the other way round, so it is
|
||||
worth stating plainly before you rely on it.
|
||||
- **No administration from apps.** Provisioning, suspension, credentials and
|
||||
audit belong to the account console; apps and API tokens are refused there.
|
||||
- [Find the user's team](/playground/teams-list/)
|
||||
- [Offer colleagues in a picker](/playground/teams-directory/)
|
||||
+27
-43
@@ -1,16 +1,14 @@
|
||||
---
|
||||
title: puter.teams.list()
|
||||
description: List the teams you belong to.
|
||||
description: Get the current user's team information.
|
||||
platforms: [websites, apps, nodejs, workers]
|
||||
---
|
||||
|
||||
<div class="info">The Teams API is in beta. Method shapes, limits, and behavior may change between releases.</div>
|
||||
|
||||
Returns the teams the caller belongs to — both those they own and those they were provisioned into.
|
||||
Get the current user's team information. If the user is not on a team, it resolves to an empty array.
|
||||
|
||||
This is also how an app discovers whether teams exist on this deployment at all: it rejects with `not_found` where the feature is off, and resolves to an empty array where it is on and the caller has no team.
|
||||
|
||||
Called from an app acting for the user, the list only includes teams whose owner opened the directory to apps (see [`listDirectory()`](/Teams/listDirectory/)); a team that has not is simply left out, the same way a team the caller isn't in would be.
|
||||
The team owner must enable the directory setting in the [Teams dashboard](https://puter.com/#teams) for the team to be returned to your app.
|
||||
|
||||
## Syntax
|
||||
|
||||
@@ -23,69 +21,55 @@ puter.teams.list(options)
|
||||
|
||||
#### `options` (Object) (optional)
|
||||
|
||||
The standard list options. All four are optional, and they decide the shape of what resolves:
|
||||
An object with the following optional properties:
|
||||
|
||||
| Call | Resolves to |
|
||||
| -- | -- |
|
||||
| No options | The whole set as an array, fetched page by page under the hood |
|
||||
| `{ limit }` | An array, capped at one page |
|
||||
| `{ cursor }` or `{ includeTotal: true }` | One `{ items, cursor? }` page. `cursor` is absent on the last page |
|
||||
| `{ stream: true }` | An async iterator of `{ items, cursor? }` pages |
|
||||
|
||||
This route is keyset-paginated, so `offset` is not accepted — passing it throws `invalid_request`. Pass `cursor` to resume from a position.
|
||||
- `limit` (Number): Maximum number of items to return in a single call.
|
||||
- `cursor` (String): A pagination cursor from a previous call. Pass the `cursor` value returned by the previous page to fetch the next one.
|
||||
- `includeTotal` (Boolean): If `true`, the result includes a `total` count of every item across all pages.
|
||||
- `stream` (Boolean): If `true`, the method returns an async iterator of pages instead of a promise, for use with `for await ... of`.
|
||||
|
||||
## Return value
|
||||
|
||||
A `Promise` that resolves to an array of `Team` objects, or to a `{ items, cursor? }` page when a pagination option is given. With `stream: true` it returns an async iterator of pages instead.
|
||||
A `Promise` that resolves to either:
|
||||
|
||||
#### `Team`
|
||||
- An array of [`Team`](/Objects/team/) objects, or
|
||||
- A page object `{ items, cursor, total }` when using `cursor` or `includeTotal` in `options`. `items` is an array of [`Team`](/Objects/team/) objects, `cursor` is present only when there are more pages, and `total` is present only when `includeTotal` is `true`.
|
||||
|
||||
| Field | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| `uid` | `string` | The team's stable identifier — pass this, not the handle. |
|
||||
| `name` | `string \| null` | Its display name. |
|
||||
| `handle` | `string \| null` | Its short handle, unique while the team exists. |
|
||||
| `isOwner` | `boolean` | Whether the caller is the owner account. |
|
||||
| `directoryEnabled` | `boolean` | Whether the owner has opened the member directory to apps. |
|
||||
| `createdAt` | `string` | When it was created. |
|
||||
With `stream: true`, the method returns an async iterator of page objects instead.
|
||||
|
||||
## Errors
|
||||
|
||||
A rejection carries an `Error` with a stable `code`:
|
||||
A rejection carries an `Error` with a `code`:
|
||||
|
||||
| Code | Meaning |
|
||||
| -- | -- |
|
||||
| `invalid_request` | Refused before reaching the server — a blank `uid`, or an `offset` on a keyset list. |
|
||||
| `token_missing` | No authentication token was presented. |
|
||||
| `token_auth_failed` | The token presented did not authenticate. |
|
||||
| `invalid_request` | `options` contains `offset`, which is not supported. Use `cursor` instead. |
|
||||
| `token_missing` | The user is not signed in. |
|
||||
| `token_auth_failed` | The user's session is invalid. |
|
||||
| `forbidden` | Called with a scoped access token. |
|
||||
| `account_is_not_verified` | The caller's email has not been confirmed. |
|
||||
| `not_found` | Teams are turned off on this deployment. |
|
||||
| `account_is_not_verified` | The user's email has not been confirmed. |
|
||||
| `too_many_requests` | The rate limit was exceeded. See [Rate Limits & Quotas](/rate-limits-and-quotas/). |
|
||||
|
||||
## Examples
|
||||
## Example
|
||||
|
||||
<strong class="example-title">Show the caller's teams, or nothing where the feature is off</strong>
|
||||
|
||||
```html
|
||||
```html;teams-list
|
||||
<html>
|
||||
<body>
|
||||
<script src="https://js.puter.com/v2/"></script>
|
||||
<script>
|
||||
(async () => {
|
||||
let teams = [];
|
||||
try {
|
||||
teams = await puter.teams.list();
|
||||
} catch (e) {
|
||||
puter.print('Teams are not available here.');
|
||||
return;
|
||||
}
|
||||
const teams = await puter.teams.list();
|
||||
|
||||
if (teams.length === 0) {
|
||||
puter.print('You are not in a team.');
|
||||
puter.print('You are not on a team.');
|
||||
return;
|
||||
}
|
||||
|
||||
for (const team of teams) {
|
||||
puter.print(`${team.name} - ${team.isOwner ? 'owner' : 'member'}<br>`);
|
||||
puter.print(`${team.name ?? team.handle ?? 'Unnamed team'}<br>`);
|
||||
puter.print(`uid: ${team.uid}<br>`);
|
||||
puter.print(`owner: ${team.isOwner}<br>`);
|
||||
puter.print(`directory open to apps: ${team.directoryEnabled}<br><br>`);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
@@ -1,19 +1,14 @@
|
||||
---
|
||||
title: puter.teams.listDirectory()
|
||||
description: Look up the user's colleagues, where the team has opened its directory to apps.
|
||||
description: Get the list of members of a team.
|
||||
platforms: [websites, apps, nodejs, workers]
|
||||
---
|
||||
|
||||
<div class="info">The Teams API is in beta. Method shapes, limits, and behavior may change between releases.</div>
|
||||
|
||||
Returns the team's member directory — the colleagues of the user your app is
|
||||
running for, active accounts only. It is consent-gated: the team's owner has to
|
||||
open the directory to apps, and until they do it rejects with `team_not_found`
|
||||
for every caller, indistinguishable from the team not existing. The same
|
||||
consent decides whether an app sees the team in [`list()`](/Teams/list/).
|
||||
Get the list of members of a team.
|
||||
|
||||
The membership is always the signed-in user's, never the app's: an app can only
|
||||
see the directory of a team its user belongs to.
|
||||
The current user must be a member of the team, and the team owner must enable the directory setting in the [Teams dashboard](https://puter.com/#teams).
|
||||
|
||||
## Syntax
|
||||
|
||||
@@ -26,77 +21,79 @@ puter.teams.listDirectory(uid, options)
|
||||
|
||||
#### `uid` (String) (required)
|
||||
|
||||
The team's `uid`, from [`list()`](/Teams/list/).
|
||||
The team's `uid`, from [`puter.teams.list()`](/Teams/list/).
|
||||
|
||||
#### `options` (Object) (optional)
|
||||
|
||||
The standard list options. All four are optional, and they decide the shape of what resolves:
|
||||
An object with the following optional properties:
|
||||
|
||||
| Call | Resolves to |
|
||||
| -- | -- |
|
||||
| No options | The whole set as an array, fetched page by page under the hood |
|
||||
| `{ limit }` | An array, capped at one page |
|
||||
| `{ cursor }` or `{ includeTotal: true }` | One `{ items, cursor? }` page. `cursor` is absent on the last page |
|
||||
| `{ stream: true }` | An async iterator of `{ items, cursor? }` pages |
|
||||
|
||||
This route is keyset-paginated, so `offset` is not accepted — passing it throws `invalid_request`. Pass `cursor` to resume from a position.
|
||||
- `limit` (Number): Maximum number of items to return in a single call.
|
||||
- `cursor` (String): A pagination cursor from a previous call. Pass the `cursor` value returned by the previous page to fetch the next one.
|
||||
- `includeTotal` (Boolean): If `true`, the result includes a `total` count of every item across all pages.
|
||||
- `stream` (Boolean): If `true`, the method returns an async iterator of pages instead of a promise, for use with `for await ... of`.
|
||||
|
||||
## Return value
|
||||
|
||||
A `Promise` that resolves to an array of
|
||||
`TeamDirectoryEntry` objects, or to a
|
||||
`{ items, cursor? }` page when a pagination option is given. With
|
||||
`stream: true` it returns an async iterator of pages instead.
|
||||
A `Promise` that resolves to either:
|
||||
|
||||
#### `TeamDirectoryEntry`
|
||||
- An array of [`TeamDirectoryEntry`](/Objects/teamdirectoryentry/) objects, or
|
||||
- A page object `{ items, cursor, total }` when using `cursor` or `includeTotal` in `options`. `items` is an array of [`TeamDirectoryEntry`](/Objects/teamdirectoryentry/) objects, `cursor` is present only when there are more pages, and `total` is present only when `includeTotal` is `true`.
|
||||
|
||||
| Field | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| `username` | `string` | A colleague's Puter username. |
|
||||
| `uuid` | `string` | Their stable account identifier. |
|
||||
With `stream: true`, the method returns an async iterator of page objects instead.
|
||||
|
||||
## Errors
|
||||
|
||||
A rejection carries an `Error` with a stable `code`:
|
||||
A rejection carries an `Error` with a `code`:
|
||||
|
||||
| Code | Meaning |
|
||||
| -- | -- |
|
||||
| `invalid_request` | Refused before reaching the server — a blank `uid`, or an `offset` on a keyset list. |
|
||||
| `token_missing` | No authentication token was presented. |
|
||||
| `token_auth_failed` | The token presented did not authenticate. |
|
||||
| `invalid_request` | `uid` is empty, or `options` contains `offset`, which is not supported. Use `cursor` instead. |
|
||||
| `token_missing` | The user is not signed in. |
|
||||
| `token_auth_failed` | The user's session is invalid. |
|
||||
| `forbidden` | Called with a scoped access token. |
|
||||
| `account_is_not_verified` | The caller's email has not been confirmed. |
|
||||
| `not_found` | Teams are turned off on this deployment. |
|
||||
| `team_not_found` | No such team, the caller is not a member of it, or the owner has not opened the directory to apps. |
|
||||
| `account_is_not_verified` | The user's email has not been confirmed. |
|
||||
| `team_not_found` | The team does not exist, the user is not a member, or the owner has not enabled the directory setting. |
|
||||
| `too_many_requests` | The rate limit was exceeded. See [Rate Limits & Quotas](/rate-limits-and-quotas/). |
|
||||
|
||||
## Examples
|
||||
## Example
|
||||
|
||||
<strong class="example-title">Suggest colleagues to share with</strong>
|
||||
|
||||
```html
|
||||
```html;teams-directory
|
||||
<html>
|
||||
<body>
|
||||
<script src="https://js.puter.com/v2/"></script>
|
||||
<select id="colleagues"><option>Loading…</option></select>
|
||||
<button id="pick">Pick</button>
|
||||
<script>
|
||||
const select = document.getElementById('colleagues');
|
||||
|
||||
(async () => {
|
||||
let teams = [];
|
||||
try {
|
||||
teams = await puter.teams.list();
|
||||
} catch (e) {
|
||||
return; // Teams are unavailable here.
|
||||
const [team] = await puter.teams.list();
|
||||
if (!team) {
|
||||
select.innerHTML = '<option>You are not on a team</option>';
|
||||
return;
|
||||
}
|
||||
for (const team of teams) {
|
||||
try {
|
||||
const colleagues = await puter.teams.listDirectory(team.uid);
|
||||
for (const person of colleagues) {
|
||||
puter.print(`${person.username}<br>`);
|
||||
}
|
||||
} catch (e) {
|
||||
// This team's directory is not open to apps.
|
||||
}
|
||||
|
||||
// Off by default, and the usual reason the list comes back empty.
|
||||
if (!team.directoryEnabled) {
|
||||
select.innerHTML = '<option>Directory is closed to apps</option>';
|
||||
return;
|
||||
}
|
||||
|
||||
const entries = await puter.teams.listDirectory(team.uid);
|
||||
select.innerHTML = '';
|
||||
for (const { username, uuid } of entries) {
|
||||
const option = document.createElement('option');
|
||||
// Store the uuid: it survives a username change.
|
||||
option.value = uuid;
|
||||
option.textContent = username;
|
||||
select.append(option);
|
||||
}
|
||||
})();
|
||||
|
||||
document.getElementById('pick').addEventListener('click', () => {
|
||||
const option = select.selectedOptions[0];
|
||||
if (option) puter.print(`${option.textContent} → ${option.value}<br>`);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,16 +7,7 @@
|
||||
const select = document.getElementById('colleagues');
|
||||
|
||||
(async () => {
|
||||
let teams;
|
||||
try {
|
||||
teams = await puter.teams.list();
|
||||
} catch (e) {
|
||||
if (e.code !== 'not_found') throw e;
|
||||
select.innerHTML = '<option>Teams are not available here</option>';
|
||||
return;
|
||||
}
|
||||
|
||||
const team = teams[0];
|
||||
const [team] = await puter.teams.list();
|
||||
if (!team) {
|
||||
select.innerHTML = '<option>You are not on a team</option>';
|
||||
return;
|
||||
|
||||
@@ -3,16 +3,7 @@
|
||||
<script src="https://js.puter.com/v2/"></script>
|
||||
<script>
|
||||
(async () => {
|
||||
let teams;
|
||||
try {
|
||||
teams = await puter.teams.list();
|
||||
} catch (e) {
|
||||
// No /teams route at all when the feature is off, so this
|
||||
// rejects rather than returning an empty list.
|
||||
if (e.code !== 'not_found') throw e;
|
||||
puter.print('Teams are not available on this Puter.');
|
||||
return;
|
||||
}
|
||||
const teams = await puter.teams.list();
|
||||
|
||||
if (teams.length === 0) {
|
||||
puter.print('You are not on a team.');
|
||||
|
||||
@@ -1388,6 +1388,20 @@ let sidebar = [
|
||||
source: '/Objects/subdomain.md',
|
||||
path: '/Objects/subdomain',
|
||||
},
|
||||
{
|
||||
title: '<code>Team</code>',
|
||||
title_tag: 'Team',
|
||||
icon: '/assets/img/object.svg',
|
||||
source: '/Objects/team.md',
|
||||
path: '/Objects/team',
|
||||
},
|
||||
{
|
||||
title: '<code>TeamDirectoryEntry</code>',
|
||||
title_tag: 'TeamDirectoryEntry',
|
||||
icon: '/assets/img/object.svg',
|
||||
source: '/Objects/teamdirectoryentry.md',
|
||||
path: '/Objects/teamdirectoryentry',
|
||||
},
|
||||
{
|
||||
title: '<code>TTSEngine</code>',
|
||||
title_tag: 'TTSEngine',
|
||||
|
||||
Reference in new issue
Block a user