@tightknitai/block-kitchen 0.8.11 → 0.9.0
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/README.md +7 -5
- package/dist/helpers.d.cts +2 -2
- package/dist/helpers.d.ts +2 -2
- package/dist/index.cjs +61 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +61 -8
- package/dist/index.js.map +1 -1
- package/dist/{palette-Bup05opK.d.cts → palette-DIbvAzRA.d.cts} +12 -8
- package/dist/{palette-Bup05opK.d.ts → palette-DIbvAzRA.d.ts} +12 -8
- package/dist/palette.d.cts +1 -1
- package/dist/palette.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -108,7 +108,7 @@ export function MyBuilderPage() {
|
|
|
108
108
|
| `loadChannels` | `() => Promise<{ id: string; name: string }[]>` | yes | Returns channels available to send to. The package never makes Slack API calls itself. |
|
|
109
109
|
| `loadSendAsUserStatus` | `() => Promise<{ canSendAsUser: boolean; oauthUrl?: string }>` | yes | Whether the current user has a Slack user-token and can post as themselves. If `canSendAsUser` is false, `oauthUrl` is shown as a "Sign in with Slack" link. |
|
|
110
110
|
| `onSend` | `(payload) => Promise<{ ok: boolean; error?: string }>` | yes | Called when the user submits the send dialog. Payload is `{ channelId, blocks, sendAsUser }`. |
|
|
111
|
-
| `editing` | `{ onLoadMessage, onUpdate, loadRecentMessages? }` | no | Opt-in edit mode. When present, the toolbar exposes "Edit message": the user pastes a Slack message link, `onLoadMessage({ link })` returns a host-computed [editability verdict](#editing-an-existing-message-opt-in), and a successful load flips the primary action to "Update message" wired to `onUpdate`. Pass `loadRecentMessages` to add a "recent messages from this app" picker beside the paste input. Omit `editing` to keep send-only behavior. |
|
|
111
|
+
| `editing` | `{ onLoadMessage, onUpdate, loadRecentMessages? }` | no | Opt-in edit mode. When present, the toolbar exposes "Edit message": the user pastes a Slack message link, `onLoadMessage({ link })` returns a host-computed [editability verdict](#editing-an-existing-message-opt-in), and a successful load flips the primary action to "Update message" wired to `onUpdate`. Pass `loadRecentMessages` to add a "recent messages from this app" picker beside the paste input; the user picks a channel first (reusing `loadChannels`) and the lookup is scoped to it. Omit `editing` to keep send-only behavior. |
|
|
112
112
|
| `loadButtonLabel` | `string` | no | Label + accessible name for the toolbar button that opens the load-message dialog (the edit-mode entry point). Defaults to `'Load message'`. Only shown when `editing` is set and no message is loaded. |
|
|
113
113
|
| `updateButtonLabel` | `string` | no | Label for the toolbar's primary button while a message is loaded for editing. It's a split button: clicking it updates the message in place; the menu beside it also offers "Send as a new message" (post the current blocks as new). Defaults to `'Review & update'`. |
|
|
114
114
|
| `confirmUpdateLabel` | `string` | no | Label for the update dialog's final confirm button. Defaults to `'Update message'` (shows `'Updating…'` while in flight). |
|
|
@@ -162,10 +162,12 @@ nothing about who can edit; the host does both.
|
|
|
162
162
|
return { ok: true };
|
|
163
163
|
},
|
|
164
164
|
// Optional: adds a "recent messages from this app" picker beside the paste
|
|
165
|
-
// input.
|
|
166
|
-
//
|
|
167
|
-
|
|
168
|
-
|
|
165
|
+
// input. The user first picks a channel (reusing `loadChannels`), then this
|
|
166
|
+
// is called with that `channelId` so the lookup scans only one channel.
|
|
167
|
+
// These are editable-by-construction (the app authored them), so picking one
|
|
168
|
+
// loads it straight into edit mode (no verdict needed).
|
|
169
|
+
loadRecentMessages: async (channelId) => {
|
|
170
|
+
const msgs = await fetchRecentAppMessages(channelId); // your code
|
|
169
171
|
return msgs.map((m) => ({
|
|
170
172
|
channelId: m.channel,
|
|
171
173
|
channelName: m.channelName,
|
package/dist/helpers.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { T as SupportedBlock } from './palette-
|
|
2
|
-
export { U as SupportedBlockType } from './palette-
|
|
1
|
+
import { T as SupportedBlock } from './palette-DIbvAzRA.cjs';
|
|
2
|
+
export { U as SupportedBlockType } from './palette-DIbvAzRA.cjs';
|
|
3
3
|
import 'react';
|
|
4
4
|
import 'slack-web-api-client';
|
|
5
5
|
|
package/dist/helpers.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { T as SupportedBlock } from './palette-
|
|
2
|
-
export { U as SupportedBlockType } from './palette-
|
|
1
|
+
import { T as SupportedBlock } from './palette-DIbvAzRA.js';
|
|
2
|
+
export { U as SupportedBlockType } from './palette-DIbvAzRA.js';
|
|
3
3
|
import 'react';
|
|
4
4
|
import 'slack-web-api-client';
|
|
5
5
|
|
package/dist/index.cjs
CHANGED
|
@@ -2851,19 +2851,25 @@ function LoadMessageDialog({
|
|
|
2851
2851
|
onOpenChange,
|
|
2852
2852
|
onLoadMessage,
|
|
2853
2853
|
loadRecentMessages,
|
|
2854
|
+
loadChannels,
|
|
2854
2855
|
onLoaded,
|
|
2855
2856
|
onOpenAsNew
|
|
2856
2857
|
}) {
|
|
2857
2858
|
const [link, setLink] = React.useState("");
|
|
2858
2859
|
const [status, setStatus] = React.useState({ kind: "idle" });
|
|
2860
|
+
const [channels, setChannels] = React.useState(null);
|
|
2861
|
+
const [channelsError, setChannelsError] = React.useState(null);
|
|
2862
|
+
const [channelId, setChannelId] = React.useState("");
|
|
2859
2863
|
const [recent, setRecent] = React.useState(null);
|
|
2860
2864
|
const [recentError, setRecentError] = React.useState(null);
|
|
2861
2865
|
const inputRef = React.useRef(null);
|
|
2862
2866
|
const onLoadMessageRef = React.useRef(onLoadMessage);
|
|
2863
2867
|
const loadRecentMessagesRef = React.useRef(loadRecentMessages);
|
|
2868
|
+
const loadChannelsRef = React.useRef(loadChannels);
|
|
2864
2869
|
React.useEffect(() => {
|
|
2865
2870
|
onLoadMessageRef.current = onLoadMessage;
|
|
2866
2871
|
loadRecentMessagesRef.current = loadRecentMessages;
|
|
2872
|
+
loadChannelsRef.current = loadChannels;
|
|
2867
2873
|
});
|
|
2868
2874
|
const hasRecent = !!loadRecentMessages;
|
|
2869
2875
|
React.useEffect(() => {
|
|
@@ -2872,15 +2878,38 @@ function LoadMessageDialog({
|
|
|
2872
2878
|
}
|
|
2873
2879
|
setLink("");
|
|
2874
2880
|
setStatus({ kind: "idle" });
|
|
2881
|
+
setChannelId("");
|
|
2882
|
+
setRecent(null);
|
|
2883
|
+
setRecentError(null);
|
|
2875
2884
|
if (!loadRecentMessagesRef.current) {
|
|
2876
|
-
|
|
2877
|
-
|
|
2885
|
+
setChannels([]);
|
|
2886
|
+
setChannelsError(null);
|
|
2887
|
+
return;
|
|
2888
|
+
}
|
|
2889
|
+
setChannels(null);
|
|
2890
|
+
setChannelsError(null);
|
|
2891
|
+
let cancelled = false;
|
|
2892
|
+
loadChannelsRef.current().then((list) => {
|
|
2893
|
+
if (!cancelled) {
|
|
2894
|
+
setChannels(list);
|
|
2895
|
+
}
|
|
2896
|
+
}).catch((e) => {
|
|
2897
|
+
if (!cancelled) {
|
|
2898
|
+
setChannelsError(e instanceof Error ? e.message : "Failed to load channels");
|
|
2899
|
+
}
|
|
2900
|
+
});
|
|
2901
|
+
return () => {
|
|
2902
|
+
cancelled = true;
|
|
2903
|
+
};
|
|
2904
|
+
}, [open]);
|
|
2905
|
+
React.useEffect(() => {
|
|
2906
|
+
if (!open || !loadRecentMessagesRef.current || !channelId) {
|
|
2878
2907
|
return;
|
|
2879
2908
|
}
|
|
2880
2909
|
setRecent(null);
|
|
2881
2910
|
setRecentError(null);
|
|
2882
2911
|
let cancelled = false;
|
|
2883
|
-
loadRecentMessagesRef.current().then((list) => {
|
|
2912
|
+
loadRecentMessagesRef.current(channelId).then((list) => {
|
|
2884
2913
|
if (!cancelled) {
|
|
2885
2914
|
setRecent(list);
|
|
2886
2915
|
}
|
|
@@ -2892,7 +2921,7 @@ function LoadMessageDialog({
|
|
|
2892
2921
|
return () => {
|
|
2893
2922
|
cancelled = true;
|
|
2894
2923
|
};
|
|
2895
|
-
}, [open]);
|
|
2924
|
+
}, [open, channelId]);
|
|
2896
2925
|
const handleLoad = async () => {
|
|
2897
2926
|
const trimmed = link.trim();
|
|
2898
2927
|
if (!trimmed) {
|
|
@@ -2996,10 +3025,33 @@ function LoadMessageDialog({
|
|
|
2996
3025
|
"or pick a recent message",
|
|
2997
3026
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-px flex-1 bg-border" })
|
|
2998
3027
|
] }),
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3028
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
3029
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "recent-channel-picker", children: "Channel" }),
|
|
3030
|
+
channels === null && !channelsError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Loading channels\u2026" }),
|
|
3031
|
+
channelsError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-destructive", children: channelsError }),
|
|
3032
|
+
channels && channels.length === 0 && !channelsError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "No public channels available." }),
|
|
3033
|
+
channels && channels.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3034
|
+
"select",
|
|
3035
|
+
{
|
|
3036
|
+
id: "recent-channel-picker",
|
|
3037
|
+
value: channelId,
|
|
3038
|
+
onChange: (e) => setChannelId(e.target.value),
|
|
3039
|
+
className: "flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
3040
|
+
children: [
|
|
3041
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, children: "Select a channel\u2026" }),
|
|
3042
|
+
channels.map((c) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: c.id, children: [
|
|
3043
|
+
"#",
|
|
3044
|
+
c.name
|
|
3045
|
+
] }, c.id))
|
|
3046
|
+
]
|
|
3047
|
+
}
|
|
3048
|
+
)
|
|
3049
|
+
] }),
|
|
3050
|
+
!channelId && channels && channels.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Select a channel to see recent messages." }),
|
|
3051
|
+
channelId && recent === null && !recentError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Loading recent messages\u2026" }),
|
|
3052
|
+
channelId && recentError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-destructive", children: recentError }),
|
|
3053
|
+
channelId && recent && recent.length === 0 && !recentError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "No recent messages from this app in this channel." }),
|
|
3054
|
+
channelId && recent && recent.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex max-h-48 flex-col gap-1 overflow-y-auto", children: recent.map((m) => {
|
|
3003
3055
|
const asUser = (m.editableVia ?? "bot") === "user";
|
|
3004
3056
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3005
3057
|
"button",
|
|
@@ -9840,6 +9892,7 @@ function BlockKitchen(props) {
|
|
|
9840
9892
|
onOpenChange: setLoadOpen,
|
|
9841
9893
|
onLoadMessage: editing.onLoadMessage,
|
|
9842
9894
|
loadRecentMessages: editing.loadRecentMessages,
|
|
9895
|
+
loadChannels,
|
|
9843
9896
|
onLoaded: (result) => {
|
|
9844
9897
|
replaceAll(result.blocks);
|
|
9845
9898
|
setEditTarget({
|