@frockbot/plugin-settings 0.0.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/frockbot.json +55 -0
- package/package.json +43 -6
- package/src/backend.test.ts +397 -0
- package/src/backend.ts +262 -0
- package/src/client/BotPanel.vue +57 -0
- package/src/client/BotSettingsSurface.vue +1076 -0
- package/src/client/BotSettingsTrigger.vue +26 -0
- package/src/client/ConnectionsSurface.vue +813 -0
- package/src/client/ModelsSurface.vue +419 -0
- package/src/client/PackageAccounts.vue +330 -0
- package/src/client/PackageCatalogSurface.vue +584 -0
- package/src/client/PackageSettingsForm.vue +150 -0
- package/src/client/PackageSettingsSection.vue +66 -0
- package/src/client/PluginsSurface.vue +412 -0
- package/src/client/PluginsTrigger.vue +62 -0
- package/src/client/UserProfileTrigger.vue +223 -0
- package/src/client/UserSettingsSurface.vue +242 -0
- package/src/client/assignment-operations.ts +22 -0
- package/src/client/bot-settings.test.ts +218 -0
- package/src/client/bot-settings.ts +150 -0
- package/src/client/index.test.ts +113 -0
- package/src/client/index.ts +78 -0
- package/src/client/package-settings.test.ts +63 -0
- package/src/client/package-settings.ts +77 -0
- package/src/client/package-surfaces.test.ts +147 -0
- package/src/client/package-surfaces.ts +93 -0
- package/src/client/user-display-name.test.ts +44 -0
- package/src/client/user-display-name.ts +16 -0
- package/src/env.d.ts +6 -0
- package/src/index.ts +1 -0
- package/src/manifest.ts +3 -0
- package/src/user.test.ts +1277 -0
- package/src/user.ts +1221 -0
- package/tsconfig.json +15 -0
- package/vite.config.ts +30 -0
- package/README.md +0 -3
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { PackageInstallationView } from "@frockbot/configuration-core";
|
|
2
|
+
import type { PluginCatalogItem } from "@frockbot/plugin-shell/shared";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Where a Package's configuration lives.
|
|
6
|
+
*
|
|
7
|
+
* Enablement and configuration are separate surfaces: Plugins turns a Package
|
|
8
|
+
* on and off, and whatever the Package declares — provider accounts, external
|
|
9
|
+
* accounts, plain settings — is edited on the surface that owns what it
|
|
10
|
+
* configures. This function is the whole routing table, so a Package that adds
|
|
11
|
+
* a Connection Type or a setting lands somewhere without an edit to a surface.
|
|
12
|
+
*/
|
|
13
|
+
export type PackageConfigurationHome =
|
|
14
|
+
"models" | "connections" | "user-settings" | "none";
|
|
15
|
+
|
|
16
|
+
/** A Package that provides a model, whose accounts and catalogs are Models'. */
|
|
17
|
+
export function isModelProviderPackage(item: PluginCatalogItem): boolean {
|
|
18
|
+
return item.capabilities.some((capability) => capability.kind === "model");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** A Package a User authorizes an external account against. */
|
|
22
|
+
export function declaresConnections(item: PluginCatalogItem): boolean {
|
|
23
|
+
return item.connectionTypes.length > 0;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function packageConfigurationHome(
|
|
27
|
+
item: PluginCatalogItem,
|
|
28
|
+
): PackageConfigurationHome {
|
|
29
|
+
if (isModelProviderPackage(item)) return "models";
|
|
30
|
+
if (declaresConnections(item)) return "connections";
|
|
31
|
+
if ((item.settings ?? []).length > 0) return "user-settings";
|
|
32
|
+
return "none";
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** The catalog entries one configuration surface is responsible for. */
|
|
36
|
+
export function packagesForHome(
|
|
37
|
+
catalog: readonly PluginCatalogItem[],
|
|
38
|
+
home: PackageConfigurationHome,
|
|
39
|
+
): PluginCatalogItem[] {
|
|
40
|
+
return catalog.filter((item) => packageConfigurationHome(item) === home);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The installation row of one Package, whatever state it is in. Absent means
|
|
45
|
+
* the Package is available to this deployment but not installed for the User.
|
|
46
|
+
*/
|
|
47
|
+
export function packageInstallation(
|
|
48
|
+
packages: readonly PackageInstallationView[],
|
|
49
|
+
packageId: string,
|
|
50
|
+
): PackageInstallationView | undefined {
|
|
51
|
+
return packages.find((candidate) => candidate.packageId === packageId);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Installed and not disabled: the only state in which a Bot may be given it. */
|
|
55
|
+
export function isPackageEnabled(
|
|
56
|
+
packages: readonly PackageInstallationView[],
|
|
57
|
+
packageId: string,
|
|
58
|
+
): boolean {
|
|
59
|
+
return packageInstallation(packages, packageId)?.state === "installed";
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Installed at all, in any state — including `disabled` and `failed`. */
|
|
63
|
+
export function isPackageInstalled(
|
|
64
|
+
packages: readonly PackageInstallationView[],
|
|
65
|
+
packageId: string,
|
|
66
|
+
): boolean {
|
|
67
|
+
return packageInstallation(packages, packageId) !== undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* What a configuration surface shows: the Packages it owns that the User has
|
|
72
|
+
* installed and enabled. A disabled Package configures nothing — its knobs are
|
|
73
|
+
* kept, and reappear when it is enabled again in Plugins.
|
|
74
|
+
*/
|
|
75
|
+
export function configurablePackages(input: {
|
|
76
|
+
catalog: readonly PluginCatalogItem[];
|
|
77
|
+
packages: readonly PackageInstallationView[];
|
|
78
|
+
home: PackageConfigurationHome;
|
|
79
|
+
}): PluginCatalogItem[] {
|
|
80
|
+
return packagesForHome(input.catalog, input.home).filter((item) =>
|
|
81
|
+
isPackageEnabled(input.packages, item.packageId),
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** The surface name a Plugins row points at, or nothing to configure. */
|
|
86
|
+
export function configurationHomeLabel(
|
|
87
|
+
home: PackageConfigurationHome,
|
|
88
|
+
): string | undefined {
|
|
89
|
+
if (home === "models") return "Models";
|
|
90
|
+
if (home === "connections") return "Connections";
|
|
91
|
+
if (home === "user-settings") return "Application settings";
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { resolveUserDisplayName } from "./user-display-name.js";
|
|
3
|
+
|
|
4
|
+
describe("resolveUserDisplayName", () => {
|
|
5
|
+
test("prefers a saved name over the authenticated session", () => {
|
|
6
|
+
expect(
|
|
7
|
+
resolveUserDisplayName({
|
|
8
|
+
savedName: "Tim",
|
|
9
|
+
sessionName: "Local developer",
|
|
10
|
+
sessionEmail: "developer@example.com",
|
|
11
|
+
}),
|
|
12
|
+
).toBe("Tim");
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("uses the session name when the saved name is the placeholder", () => {
|
|
16
|
+
expect(
|
|
17
|
+
resolveUserDisplayName({
|
|
18
|
+
savedName: "FrockBot user",
|
|
19
|
+
sessionName: "Local developer",
|
|
20
|
+
sessionEmail: "developer@example.com",
|
|
21
|
+
}),
|
|
22
|
+
).toBe("Local developer");
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("uses the session email when its name is the placeholder", () => {
|
|
26
|
+
expect(
|
|
27
|
+
resolveUserDisplayName({
|
|
28
|
+
savedName: "FrockBot user",
|
|
29
|
+
sessionName: "FrockBot user",
|
|
30
|
+
sessionEmail: " developer@example.com ",
|
|
31
|
+
}),
|
|
32
|
+
).toBe("developer@example.com");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("uses the placeholder when every candidate is blank", () => {
|
|
36
|
+
expect(
|
|
37
|
+
resolveUserDisplayName({
|
|
38
|
+
savedName: " ",
|
|
39
|
+
sessionName: "",
|
|
40
|
+
sessionEmail: " ",
|
|
41
|
+
}),
|
|
42
|
+
).toBe("FrockBot user");
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isChosenUserName,
|
|
3
|
+
USER_PROFILE_PLACEHOLDER_NAME_V1,
|
|
4
|
+
} from "@frockbot/configuration-core";
|
|
5
|
+
|
|
6
|
+
export function resolveUserDisplayName(input: {
|
|
7
|
+
savedName?: string;
|
|
8
|
+
sessionName?: string;
|
|
9
|
+
sessionEmail?: string;
|
|
10
|
+
}): string {
|
|
11
|
+
if (isChosenUserName(input.savedName)) return input.savedName.trim();
|
|
12
|
+
if (isChosenUserName(input.sessionName)) return input.sessionName.trim();
|
|
13
|
+
|
|
14
|
+
const sessionEmail = input.sessionEmail?.trim();
|
|
15
|
+
return sessionEmail || USER_PROFILE_PLACEHOLDER_NAME_V1;
|
|
16
|
+
}
|
package/src/env.d.ts
ADDED
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default, default as manifest } from "./manifest.js";
|
package/src/manifest.ts
ADDED