Microsoft teams bot adaptive card carousel deleting a card

老子叫甜甜 提交于 2021-01-20 07:55:30

问题


I am using Microsoft teams bot with nodejs. I am rendering a carousel of adaptive cards with action on each card. My requirement is to delete an individual card out on which the action was clicked. Is it possible?

Current code looks like below. i have given a try to deleteActive but that deletes entire carousel

const {
    TurnContext,
    TeamsActivityHandler,
    CardFactory,
    AttachmentLayoutTypes,
    ActionTypes
} = require('botbuilder');

class TeamsConversationBot extends TeamsActivityHandler {
    constructor() {
        super();
        this.onMessage(async (context:any, next:any) => {
            TurnContext.removeRecipientMention(context.activity);
            console.log("context activigty at the begin is:" + JSON.stringify(context.activity))
            let msg = context.activity.text
            let action = context.activity.value

            if(msg.startsWith('lead')){
                msg = 'lead'
            }

            if(action !== undefined){
                console.log("user did some action on a card")
                msg = action.action
            }

            switch (msg) {
                case 'lead':
                        await this.lead(context)
                        break;
                case 'qualify_lead':
                        await this.qualifyLead(context)
                        break;
            }
            await next();
        });
    }


    /**
     * 
     * @param context this method does a lead qualification
     */
    async qualifyLead(context:any){
        console.log("in qualifyLead:" + JSON.stringify(context.activity))
        //await context.deleteActivity(context.activity.replyToId)

        const leadId = context.activity.value.objectId
        console.log("Lead to qualify is:" + leadId)


        await context.sendActivity('Lead is qualified')
    }


/**
    * Search contact by name
    * @param context
    * @param keyword 
*/ 
async lead(context:any){
    console.log("Start of lead with context:" + JSON.stringify(context))
    const cardArr = []
    let items = [
        {"Name": 'x', "LeadId": "1"},
        {"Name": 'a', "LeadId": "2"},
        {"Name": 'b', "LeadId": "3"},
        {"Name": 'c', "LeadId": "4"},
        {"Name": 'd', "LeadId": "5"}
    ]

     for(const item of items){
        const header =  {
            "type": "TextBlock",
            "size": "Medium",
            "weight": "Bolder",
            "text": item.Name
        }



    const actions = [
        {
            "type": "Action.Submit",
            "title": "Qualify",
            "data": { "action" : "qualify_lead", "objectId" : item.LeadId }
        }
       ]


   const acard = CardFactory.adaptiveCard(
    {
        "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
        "type": "AdaptiveCard",
        "version": "1.0",
        "body": [
            header,
            ''
            ],
           "actions": actions
         }
     )

    cardArr.push(acard)
    console.log("payload is::::" + JSON.stringify(acard))
        }

    const reply = {
        "attachments" : cardArr,
        "attachmentLayout" : AttachmentLayoutTypes.Carousel
    }

    await context.sendActivity(reply);
}

}

module.exports.TeamsConversationBot = TeamsConversationBot;

回答1:


As with this other answer, the answer will be similar to this one. I can see you're trying to use TypeScript but your code deviates very little from JavaScript so I'll just write my answer in JavaScript.

First, you'll need a way of saving state for your [carousel] so you can update the [carousel]'s activity.

this.carouselState = this.conversationState.createProperty('carouselState');

You'll want a consistent way to generate your [carousel] that you can use when you send the [carousel] initially and when you update the [carousel].

createCarousel(batchId, leads)
{
    const cardArr = [];

    let items = [
        { "Name": 'x', "LeadId": 1 },
        { "Name": 'a', "LeadId": 2 },
        { "Name": 'b', "LeadId": 3 },
        { "Name": 'c', "LeadId": 4 },
        { "Name": 'd', "LeadId": 5 }
    ];

    items = items.filter(item => leads.includes(item.LeadId));

    for (const item of items) {
        const header = {
            "type": "TextBlock",
            "size": "Medium",
            "weight": "Bolder",
            "text": item.Name
        };

        const actions = [
            {
                "type": "Action.Submit",
                "title": "Qualify",
                "data": { [KEYACTION]: ACTIONQUALIFYLEAD, [KEYOBJECTID]: item.LeadId, [KEYBATCHID]: batchId }
            }
        ];

        const acard = CardFactory.adaptiveCard(
            {
                "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
                "type": "AdaptiveCard",
                "version": "1.0",
                "body": [
                    header
                ],
                "actions": actions
            }
        );

        cardArr.push(acard);
    }

    return {
        "type": "message",
        "attachments": cardArr,
        "attachmentLayout": AttachmentLayoutTypes.Carousel
    };
}

This is similar to your code but there are some important differences. First, I'm filtering the items array to allow for fewer items, which is how you'll end up deleting cards from your carousel. Second, I'm including a "batch ID" in each action's data, which is how your bot will know which activity to update when it receives the action's payload. Also, this isn't relevant to your question but I'm using string constants instead of string literals most everywhere I expect to use that string more than once, which is a practice I follow to avoid typo-related bugs etc.

Using this function, you can send the [carousel] initially like this

async testCarousel(turnContext) {
    const batchId = Date.now();
    const leads = [1, 2, 3, 4, 5];
    const reply = this.createCarousel(batchId, leads);
    const response = await turnContext.sendActivity(reply);
    const dict = await this.carouselState.get(turnContext, {});

    dict[batchId] = {
        [KEYACTIVITYID]: response.id,
        [KEYLEADS]: leads
    };
}

And you can update the [carousel] in response to the card's [qualify] submit action like this

async handleSubmitAction(turnContext) {
    const value = turnContext.activity.value;

    switch (value[KEYACTION]) {
        case ACTIONQUALIFYLEAD:
            const dict = await this.carouselState.get(turnContext, {});
            const batchId = value[KEYBATCHID];
            const info = dict[batchId];
            if (info) {
                const leads = info[KEYLEADS];
                const objectId = value[KEYOBJECTID];
                var index = leads.indexOf(objectId);
                if (index !== -1) leads.splice(index, 1);
                const update = this.createCarousel(batchId, leads);
                update.id = info[KEYACTIVITYID];
                if (update.attachments.length) {
                    await turnContext.updateActivity(update);
                } else {
                    await turnContext.deleteActivity(update.id);
                }
            }
            break;
    }
}


来源:https://stackoverflow.com/questions/59405348/microsoft-teams-bot-adaptive-card-carousel-deleting-a-card

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!