slackapi / deno-slack-sdk

SDK for building Run on Slack apps using Deno
https://api.slack.com/automation
151 stars 27 forks source link

[QUERY] Documentation/Examples on Canvas functions #303

Closed markfoden closed 2 months ago

markfoden commented 3 months ago

I want to use the new canvas functions and am looking for information and examples on structuring complex pages.

There is a one-line example in the samples here but I need a bit more

I'm looking for a detailed definition of expanded_rich_text in particular how to set up placeholders / canvas variables, tables, headings (ie 1/2/3 level headings rather than the standard Header block) and checkboxes.

A section on Canvases in the Block Kit Builder would be great, but I guess it's early days

Glad of any help - thanks

filmaj commented 3 months ago

Thanks for submitting this issue! Makes a lot of sense, let me raise this with the team and see what we could do here.

markfoden commented 3 months ago

@filmaj That's great. In the short term just a few hints would probably do. Thanks

markfoden commented 3 months ago

@filmaj Ah, I've found that some functions like canvas_copy are only available for Enterprise Grid customers. Which strikes me as a little odd. What's the best way to raise this issue? I've asked a question on the Slack Help desk but the person helping me wasn't aware that functions were restricted in this way.

filmaj commented 3 months ago

Noted, let me see if I can at least dig up a schema/reference for expanded_rich_text...

It is mostly based on the same schema as for rich_text, which the Block Kit documentation dives into decently well as a kind of reference doc. In particular, you can reuse rich_text_section, rich_text_preformatted and rich_text_quote as sub-elements as described in this document.

rich_text_list is the same as described in this document, too, with one exception: the style property allows for a few additional options, and specifically allows for any of the following values: ["bullet", "ordered", "checked", "unchecked"]. I haven't tested this myself, but it seems like using checked and unchecked would be used to implement a checklist.

Expanded rich text also supports two other sub-elements. I will paste in the relevant JSON schema bits here but note I haven't tested this out much so fair warning!

rich_text_header

    "required": ["type", "elements"],
    "properties": {
        "type": {
            "type": "string",
            "enum": ["rich_text_header"]
        },
        "elements": {
            "$ref": "../rich_text_elements.json#" // same as `rich_text_section`: https://api.slack.com/reference/block-kit/blocks#rich_text_section
        },
        "level": { // <-- I assume this sets the header level
            "type": "integer",
            "minimum": 1,
            "maximum": 3
        }
    }

rich_text_divider

This one's very simple: only accepts a type property:

    "required": ["type"],
    "properties": {
        "type": {
            "type": "string",
            "enum": ["rich_text_divider"]
        }
    }

Hope that helps at least to unblock playing around with this stuff; once we have a better answer on the documentation side I will update this issue.

filmaj commented 3 months ago

@filmaj Ah, I've found that some functions like canvas_copy are only available for Enterprise Grid customers. Which strikes me as a little odd. What's the best way to raise this issue? I've asked a question on the Slack Help desk but the person helping me wasn't aware that functions were restricted in this way.

The best way to get this kind of feedback in front of the powers-that-be that decide on priority and such product decisions is by emailing feedback@slack.com. This is a formal intake process that the relevant decision makers regularly review. Possibly you've already done this if you say you've been interacting with the Slack help desk. I would suggest making it clear that your feedback message / help desk ticket content is not about seeking help with a problem but rather ensuring your voice is heard about a product decision (such as gating features behind specific Slack paid plans). This should streamline the help desk staff interaction to get your feedback filed away in the proper place.

Wish I had more influence in this department but alas, above my pay grade! Apologies.

markfoden commented 3 months ago

@filmaj I tried the function content below. It works with just the RICH TEXT SECTION but not when I add the RICH TEXT HEADER. It errors with _invalidblocks. Have I interpreted the schema correctly?

 {
        "type": "rich_text",
        "elements": [
          // RICH TEXT HEADER
          {
            "type": "rich_text_header",
            "elements": [{ "type": "text", "text": "My heading" }],
            "level": 2
          },
          // RICH TEXT SECTION
          {
            "type": "rich_text_section",
            "elements": [{ "type": "text", "text": "My text" }],
          },
        ],
      },
markfoden commented 3 months ago

I just tested the unchecked style on a _rich_textlist block. I get _invalidblocks. It works fine when switched to bullet.


      {
        "type": "rich_text",
        "elements": [
          // RICH TEXT HEADER
          // {
          //   "type": "rich_text_header",
          //   "elements": [{ "type": "text", "text": "My heading" }],
          //   "level": 2
          // },
          // RICH TEXT SECTION
          {
            "type": "rich_text_section",
            "elements": [{ "type": "text", "text": "My text" }],
          },
          // RICH TEXT LIST
          {
            "type": "rich_text_list",
            "style": "unchecked",
            "elements": [
              {
                "type": "rich_text_section",
                "elements": [
                  {
                    "type": "text",
                    "text": "list item one"
                  }
                ]
              },
              {
                "type": "rich_text_section",
                "elements": [
                  {
                    "type": "text",
                    "text": "list item two"
                  }
                ]
              }
            ]
          },
        ],
      },
    ]```
filmaj commented 3 months ago

I'll spend some time today playing with this and report back.. sorry about the experience.

filmaj commented 3 months ago

OK I'm back! Took me a while to figure this out, but I got my app working w/ canvas steps. Here's what's needed:

Manifest addition

First you need to ensure you have the following in your app manifest:

  features: {
    appHome: {
      messagesTabEnabled: true,
      messagesTabReadOnlyEnabled: false,
    },
  },

Full expanded_rich_text example

I think the missing key in the last payload you shared, @markfoden , is that you have type: "rich_text", whereas we want to use type: "expanded_rich_text". Here's a full example that worked with me, using all the expanded rich text elements:

[
    {
        "type": "expanded_rich_text",
        "elements": [
            {
                "type": "rich_text_header",
                "elements": [
                    {
                        "type": "text",
                        "text": "Hello world"
                    }
                ],
                "level": 1
            },
            {
                "type": "rich_text_list",
                "style": "unchecked",
                "indent": 0,
                "elements": [
                    {
                        "type": "rich_text_section",
                        "elements": [
                            {
                                "type": "text",
                                "text": "one"
                            }
                        ]
                    }
                ],
                "border": 0
            },
            {
                "type": "rich_text_list",
                "style": "checked",
                "indent": 1,
                "elements": [
                    {
                        "type": "rich_text_section",
                        "elements": [
                            {
                                "type": "text",
                                "text": "two"
                            }
                        ]
                    }
                ],
                "border": 0
            },
            {
                "type": "rich_text_divider"
            }
        ]
    }
]

Let me know how that goes for you!

markfoden commented 3 months ago

@filmaj That looks just the job. Very grateful.

Can I ask for a couple more things...

As ever thank you for your help

filmaj commented 3 months ago

Is there a definition for tables yet?

Not yet but a Table Block element is in the works and we plan on releasing it very soon! I don't want to provide a release date on that but my understanding is it is imminent.

How to implement a link? I read something that said it's better not to use markdown but whilst there are references for bold, italics etc in rich text I couldn't find one for links.

rich_text_section, rich_text_preformatted and rich_text_quote all allow for their elements array to accept a type:link element. rich_text_lists, on the other hand, accept rich_text_section in its elements array, which in turn can contain links.

markfoden commented 3 months ago

@filmaj All cool, now working. Thank you very much

I guess the tables feature will be part of the expanded_rich_text definition and since documentation seems to be lagging release how could I spot when the tables feature is ready?

filmaj commented 3 months ago

It should be announced in our changelog on api.slack.com.

I'll keep this issue open until we have better documentation up for expanded_rich_text et al.

harshbhardwaj29 commented 2 months ago

I have tried to use both Schema.slack.functions.CanvasCreate and Schema.slack.functions.ChannelCanvasCreate, failed when invoked using web-hook trigger with 'internal_error' and 'file_not_found' errors.

Note : for testing purpose, i have pass the hard code values directly. workflow:

import { DefineWorkflow, Schema } from "deno-slack-sdk/mod.ts";

export const SampleCanvasWorkflowDefinition = DefineWorkflow({
  callback_id: "dr_canvas_function",
  title: "Canvas",
  description: "dealroom canvas",
  input_parameters: {
    properties: {
      message: {
        type: Schema.types.string,
        description: "Message to send",
      },
      channel: {
        type: Schema.slack.types.channel_id,
        description: "channel to send message to",
      },
      description: {
        type: Schema.types.string,
        description: "description to send",
      },
    },
    required: ["message", "channel", "description"],
  },
  output_parameters: {
    properties: {
      message: {
        type: Schema.types.string,
        description: "Message that was sent",
      },
      channel: {
        type: Schema.slack.types.channel_id,
        description: "channel the message was sent to",
      },
      description: {
        type: Schema.types.string,
        description: "description to send",
      },
      canvas_id: {
        type: Schema.slack.types.canvas_id,
        description: "Canvas link",
        title: "Canvas link",
      },
    },
    required: ["message", "channel", "description", "canvas_id"],
  },
});

SampleCanvasWorkflowDefinition.addStep(
  Schema.slack.functions.CanvasCreate,
  {
    title: "Hello world",
    owner_id: "U05BJ6XSS82",
    content: [
      {
        "type": "rich_text",
        "elements": [
          {
            "type": "rich_text_section",
            "elements": [{ "type": "text", "text": "Hello new canvas" }],
          },
        ],
      },
    ],
  },
);

trigger:

import { Trigger } from "deno-slack-api/types.ts";
import { SampleWorkflowDefinition } from "../workflows/sample_workflow.ts";
import { TriggerTypes } from "deno-slack-api/mod.ts";

const trigger: Trigger<typeof SampleWorkflowDefinition.definition> = {
  type: TriggerTypes.Webhook,
  name: "sends message to my fav channel",
  description: "runs the example workflow",
  workflow: "#/workflows/sample_function",
  inputs: {
    message: {
      value: "{{data.message}}",
    },
    channel: {
      value: "{{data.channel}}",
    },
    description: {
      value: "{{data.desciption}}",
    },
  },
};

export default trigger;

Screenshot 2024-04-20 at 1 39 53 AM

@filmaj @markfoden any idea about the errors and what is missed

filmaj commented 2 months ago

@harshbhardwaj29 use "type": "expanded_rich_text" instead of "type": "rich_text"

harshbhardwaj29 commented 2 months ago

@filmaj thanks that helps, any idea of the other error:Schema.slack.functions.ChannelCanvasCreate, getting odd error of 'file_not_found' and first message in my screenshot.

filmaj commented 2 months ago

Can you share the code for how you invoke ChannelCanvasCreate?

harshbhardwaj29 commented 2 months ago

@filmaj My workflow

import { DefineWorkflow, Schema } from "deno-slack-sdk/mod.ts";

export const SampleCanvasWorkflowDefinition = DefineWorkflow({
  callback_id: "dr_canvas_function",
  title: "Dealroom Canvas",
  description: "canvas",
  input_parameters: {
    properties: {
      message: {
        type: Schema.types.string,
        description: "Message to send",
      },
      channel: {
        type: Schema.slack.types.channel_id,
        description: "channel to send message to",
      },
      description: {
        type: Schema.types.string,
        description: "description to send",
      },
    },
    required: ["message", "channel", "description"],
  },
  output_parameters: {
    properties: {
      message: {
        type: Schema.types.string,
        description: "Message that was sent",
      },
      channel: {
        type: Schema.slack.types.channel_id,
        description: "channel the message was sent to",
      },
      description: {
        type: Schema.types.string,
        description: "description to send",
      },
      canvas_id: {
        type: Schema.slack.types.canvas_id,
        description: "Canvas link",
        title: "Canvas link",
      },
    },
    required: ["message", "channel", "description", "canvas_id"],
  },
});

SampleCanvasWorkflowDefinition.addStep(
  Schema.slack.functions.ChannelCanvasCreate,
  {
    channel_id: SampleCanvasWorkflowDefinition.inputs.channel,
    canvas_create_type: "template",
    canvas_template_id: "TEM123456",
    content: [
      {
        "type": "expanded_rich_text",
        "elements": [
          {
            "type": "rich_text_section",
            "elements": [{ "type": "text", "text": "Hello new canvas" }],
          },
        ],
      },
    ],
  },
);

trigger for invoking workflow:

import { Trigger } from "deno-slack-api/types.ts";
import { SampleCanvasWorkflowDefinition } from "../workflows/canvas_workflow.ts";
import { TriggerTypes } from "deno-slack-api/mod.ts";

const dealroomCanvasCreateTrigger: Trigger<
  typeof SampleCanvasWorkflowDefinition.definition
> = {
  type: TriggerTypes.Webhook,
  name: "send canvas message to dealroom channel",
  description: "runs the example workflow",
  workflow: "#/workflows/dealroom_canvas_function",
  inputs: {
    message: {
      value: "{{data.message}}",
    },
    channel: {
      value: "{{data.channel}}",
    },
    description: {
      value: "{{data.desciption}}",
    },
  },
};

export default dealroomCanvasCreateTrigger;
harshbhardwaj29 commented 2 months ago

@filmaj Also experimented this

import { DefineWorkflow, Schema } from "deno-slack-sdk/mod.ts";

export const SampleCanvasWorkflowDefinition = DefineWorkflow({
  callback_id: "dealroom_canvas_function",
  title: "Dealroom Canvas",
  description: "dealroom canvas",
  input_parameters: {
    properties: {
      message: {
        type: Schema.types.string,
        description: "Message to send",
      },
      channel: {
        type: Schema.slack.types.channel_id,
        description: "channel to send message to",
      },
      description: {
        type: Schema.types.string,
        description: "description to send",
      },
    },
    required: ["message", "channel", "description"],
  },
  output_parameters: {
    properties: {
      message: {
        type: Schema.types.string,
        description: "Message that was sent",
      },
      channel: {
        type: Schema.slack.types.channel_id,
        description: "channel the message was sent to",
      },
      description: {
        type: Schema.types.string,
        description: "description to send",
      },
      canvas_id: {
        type: Schema.slack.types.canvas_id,
        description: "Canvas link",
        title: "Canvas link",
      },
    },
    required: ["message", "channel", "description", "canvas_id"],
  },
});

// SampleCanvasWorkflowDefinition.addStep(Schema.slack.functions.CanvasCreate, {
//   title: "Dealroom Canvas",
//   owner_id: "U05BJ6XSS82",
// });

SampleCanvasWorkflowDefinition.addStep(
  Schema.slack.functions.ChannelCanvasCreate,
  {
    channel_id: SampleCanvasWorkflowDefinition.inputs.channel,
    content: [
      {
        "type": "expanded_rich_text",
        "elements": [
          {
            "type": "rich_text_section",
            "elements": [{ "type": "text", "text": "Hello new canvas" }],
          },
        ],
      },
    ],
  },
);

Screenshot 2024-04-20 at 2 39 34 AM

The user i am using is the workspace owner

filmaj commented 2 months ago

What Slack plan is your workspace on?

harshbhardwaj29 commented 2 months ago

What Slack plan is your workspace on?

@filmaj I am on paid plan (pro)

filmaj commented 2 months ago

Not sure, best to ask customer support by emailing feedback@slack.com

harshbhardwaj29 commented 2 months ago

@filmaj i have one question: suppose i have slack bot, and i other workspace W1 where slack bot is a part of:

now i can send a bot message in channel on workspace W1 using slack user of workspace W1, now using same access token, i want to create canvas in same channel, would it be possible to do so

filmaj commented 2 months ago

@harshbhardwaj29 can you open a new issue with more details? I'd like to keep this issue focussed on the original issue submitted. Please include which SDK you are using to build the bot, and what you mean by 'sending bot message using slack user' - as that is unclear.

filmaj commented 2 months ago

Expanded rich text documentation has landed which should be much improved. I will close this but if there are other issues here feel free to re-open or open a new issue.