Exemplo n.º 1
0
def create_two_col_card(device, greetingtext, fields, time):
    greeting = TextBlock(greetingtext,
                         size=FontSize.LARGE,
                         horizontalAlignment=HorizontalAlignment.CENTER,
                         color=Colors.ACCENT)
    col1 = []
    col2 = []
    for field in fields:
        name = field[0]
        value = field[1]
        col1.append(TextBlock(text=str(name), size=FontSize.SMALL))
        col2.append(TextBlock(text=str(device[value]), size=FontSize.SMALL))

    col1.append(TextBlock(text=str('As Of'), size=FontSize.SMALL))
    col2.append(TextBlock(text=str(time), size=FontSize.SMALL))
    column1 = Column(items=col1)
    column2 = Column(items=col2)
    table = ColumnSet(columns=[column1, column2])
    card = AdaptiveCard(body=[greeting, table])
    attachment = {
        "contentType": CONTENT_TYPE,
        "content": card.to_dict(),
    }
    print(card.to_json(pretty=True))
    return attachment
Exemplo n.º 2
0
def static_new_instance(tags, instanceid):

    greeting = TextBlock(
        f"New EC2 Instance ID: {str(instanceid)}  "
        f"Has Been Created Please Validate Your Tags",
        horizontalAlignment=HorizontalAlignment.CENTER,
        size=FontSize.LARGE)

    _data_classification = Fact(title="Data Classification",
                                value=str(tags.dataclassification))
    _environment = Fact(title='Environment', value=str(tags.environment))
    _resourc_oewner = Fact(title='ResourceOwner',
                           value=str(tags.resourceowner))
    _cisco_mail_alias = Fact(title="Cisco Mail Alias",
                             value=str(tags.ciscomailalias))
    _data_taxonomy = Fact(title="Data Taxonomy", value=str(tags.datataxonomy))
    _app_name = Fact(title="Application Name", value=str(tags.appname))
    info = FactSet(facts=[
        _data_classification, _environment, _resourc_oewner, _cisco_mail_alias,
        _data_taxonomy, _app_name
    ])
    approve = Submit(title="Approve", data={"instid": instanceid})
    card = AdaptiveCard(body=[greeting, info], actions=[approve])
    attachment = {
        "contentType": CONTENT_TYPE,
        "content": card.to_dict(),
    }
    return attachment
Exemplo n.º 3
0
 def send_card(self, userObjId, issueType, dbObj, webexObj):
     print("-->> AdaptiveCard.send_card():")
     IssueActionMapping = {
         'pri':
         '\n\n These details might help:\n 1. show isdn status \n 2. show controller',
         'gateway':
         '\n\n These details might help: \n 1. show ccm-manager\n 2. show isdn status \n 3. Check for crash files\n 4. Check for uptime'
     }
     AlertTextMapping = {
         'pri': 'PRI is Down',
         'gateway': 'Gateway is unreachable'
     }
     # greeting = TextBlock("Critical Case Alert Notification",weight="bolder",horizontalAlignment="center")
     alertType = TextBlock(f'Alert Type:{AlertTextMapping[issueType]}',
                           color="attention")
     reqAction = TextBlock(f'{IssueActionMapping[issueType]}')
     CCANSLogo = Image(url=self.Main_Banner_with_text)
     submit = Submit(title="ACK", )
     card = AdaptiveCard(body=[CCANSLogo, alertType, reqAction],
                         actions=[submit])
     attachment = {
         "contentType": "application/vnd.microsoft.card.adaptive",
         "content": card.to_dict(),
     }
     # roomId = inMsg['data']['roomId']
     webexObj.ccans_api.messages.create(toPersonId=userObjId,
                                        text="Card: Crtitical Case Alert",
                                        attachments=[attachment])
Exemplo n.º 4
0
    def generate_model_response(switch_data, original_model=None):
        items = []
        if original_model:
            items.append(
                TextBlock(text=f"The {original_model} is equivalent to the",
                          size="Small",
                          weight="Lighter"))
        items.append(
            TextBlock(text=f"{switch_data.model}",
                      size="ExtraLarge",
                      color="Accent",
                      spacing=None))
        title = Container(items=items)

        facts = []
        for attr, description in models.Switch._name_mapping.items():
            value = vars(switch_data).get(attr, None)
            if value:
                facts.append(Fact(description, value))

        factset = FactSet(facts)

        card = AdaptiveCard(body=[title, factset],
                            fallbackText=str(switch_data))

        attachment = {
            "contentType": "application/vnd.microsoft.card.adaptive",
            "content": card.to_dict(),
        }

        return attachment
Exemplo n.º 5
0
    def create_feedback_card(self):
        greeting = TextBlock("Did you like the new chatbot?",
                             size="medium",
                             weight="bolder")
        act1 = Submit(title="Yes", data="yes")
        act2 = Submit(title="No", data="no")

        card1 = AdaptiveCard(body=greeting, actions=[act1, act2])
        card1_json = card1.to_json(pretty=True)
        return card1_json
Exemplo n.º 6
0
def get_pr_list_output_card(userid, results):
    body = []
    body.append(TextBlock(f"Latest PRs for **{userid}**", isSubtle=True))

    repo = 'https://gh-xr.scm.engit.cisco.com/xr/iosxr'
    for r in results:
        pr_markdown = "[{n}]({r}/pull/{n})".format(n=r['number'], r=repo)
        number = Column([
            TextBlock(pr_markdown,
                      weight='bold',
                      horizontalAlignment=HorizontalAlignment.LEFT),
        ],
                        separator=True,
                        width='60px')
        title = Column([
            TextBlock(r['title'],
                      weight='bold',
                      horizontalAlignment=HorizontalAlignment.LEFT),
        ],
                       separator=True,
                       width='500px')

        state = Column([
            TextBlock(f"` {r['state']} `",
                      horizontalAlignment=HorizontalAlignment.LEFT),
        ],
                       separator=True,
                       width='150px')
        head_markdown = "[{h}]({r}/tree/{h})".format(h=r['head'], r=repo)
        head = Column([
            TextBlock(head_markdown,
                      weight='bold',
                      horizontalAlignment=HorizontalAlignment.LEFT),
        ],
                      separator=True,
                      width='300px')
        arrow = Column([
            TextBlock('➔', color=Colors.ACCENT),
        ],
                       separator=True,
                       width='50px')
        base_markdown = "[{b}]({r}/tree/{b})".format(b=r['base'], r=repo)
        base = Column([
            TextBlock(base_markdown,
                      weight='bold',
                      horizontalAlignment=HorizontalAlignment.LEFT),
        ],
                      separator=True,
                      width='100px')

        container = Container([
            ColumnSet([number, title]),
            ColumnSet([state, head, arrow, base])
        ],
                              separator=True,
                              spacing=Spacing.MEDIUM)
        body.append(container)

    return AdaptiveCard(body=body)
Exemplo n.º 7
0
def get_support_input_card():
    greeting1 = TextBlock("PR number (optional)")
    number = Number('support.pr_number', placeholder='12345')
    greeting2 = TextBlock("Issue details")
    query = Text('support.details', placeholder="...")
    submit = Submit(title="Submit")

    return AdaptiveCard(body=[greeting1, number, greeting2, query],
                        actions=[submit])
Exemplo n.º 8
0
    def generate_edit_response(switch):
        title = Container(items=[
            TextBlock(text=f"Currently editing switch",
                      size="Small",
                      weight="Lighter"),
            TextBlock(text=f"{switch.model}",
                      size="ExtraLarge",
                      color="Accent",
                      spacing=None)
        ])

        items = []
        vars(models.Switch).keys()
        for attr, description in models.Switch._name_mapping.items():
            try:
                value = vars(switch).get(attr, None)
                # Don't append null values or internal attributes
                if attr[0] != '_':
                    if type(value) == bool:
                        items.append(Toggle(description, attr, value=value))
                    else:
                        items.append(TextBlock(text=f"{description}"))
                        items.append(
                            Text(attr, placeholder=f"{description}", value=value))

            except AttributeError:
                continue

        submit = Submit(title="Update")

        body = Container(items=items)

        card = AdaptiveCard(
            body=[title, body],
            actions=[submit],
            fallbackText=str(
                "Adaptive cards need to be enabled to use this feature."))

        attachment = {
            "contentType": "application/vnd.microsoft.card.adaptive",
            "content": card.to_dict(),
        }

        return attachment
Exemplo n.º 9
0
def make_card(name):
    card_body = []

    logo = Image(
        "https://gist.githubusercontent.com/sQu4rks/82ce8e2f0aa9f37413b7913fc1c0487b/raw/3152f2158c8b99e114ae0803a921b1ff26c15709/welcome-banner.jpg"
    )
    card_body.append(logo)

    greeting = TextBlock(MESSAGE.format(name=name))
    card_body.append(greeting)

    card = AdaptiveCard(body=card_body)

    attachment = {
        "contentType": "application/vnd.microsoft.card.adaptive",
        "content": card.to_dict(),
    }

    return attachment
Exemplo n.º 10
0
def get_search_output_card(query, results):
    body = []
    body.append(TextBlock(f"Results for **{query}**", isSubtle=True))

    for r in results:
        url = "[{}]({})".format(r['title'], r['url'])
        body.append(TextBlock(url, weight='bold', color=Colors.ACCENT))
        body.append(TextBlock(r['snippet'], wrap=True, separator=True))
        body.append(TextBlock(''))

    return AdaptiveCard(body=body)
Exemplo n.º 11
0
def get_card_from_question_set(qs):
    body = []
    intro = TextBlock(f"## {qs.name}")
    body.append(intro)

    # Create a input for each of the questions
    for q in qs.questions.all():
        input_id = f"{qs.id}#{q.id}"

        label = TextBlock(f"**{q.text}**")
        body.append(label)

        if q.question_type == Question.TYPE_TEXT:
            field = Text(input_id)
            body.append(field)
        elif q.question_type == Question.TYPE_MC:
            string_choices = re.search(r'\((.*?)\)', q.text).group(1).split(",")

            choices = []
            for str_choice in string_choices:
                c = Choice(str_choice, str_choice)
                choices.append(c)
            field = Choices(choices, input_id)
            body.append(field)

    submit_action = {
        'type': "Action.Submit",
        'title': "Send Survey", 
        'data': {
            'question_set': str(qs.id)
        }
    }

    card = AdaptiveCard(body=body, actions=[])

    ret = card.to_dict()
    ret['actions'].append(submit_action)

    return ret
Exemplo n.º 12
0
    def generate_list_items_card(self) -> Attachment:
        from pyadaptivecards.card import AdaptiveCard
        from pyadaptivecards.components import TextBlock
        from pyadaptivecards.actions import Submit, OpenUrl, ShowCard
        
        order_number = '001'
        body = []
        greeting = TextBlock(f'Order #{order_number}', weight='bolder', size='medium')
        submit = Submit(title='Confirm Order')
        date = TextBlock(str(datetime.now().strftime('%a. %d of %b, %Y at %H:%M')), size='small')
        body.append(greeting)
        body.append(date)

        quantity_column_items = [TextBlock('Quantity', weight='bolder')]
        item_column_items = [TextBlock('Item', weight='bolder')]

        for item in self.item_list:

            if item.unit == '' or item.quantity != 0:
                item_column_items.append(TextBlock(f'{item.description.capitalize()}'))
                quantity_column_items.append(TextBlock(f'{item.quantity}'))
            else:
                item_column_items.append(TextBlock(f'{item.description.capitalize()}'))
                quantity_column_items.append(TextBlock(f'{item.weight} {item.unit.capitalize()}'))

        card = AdaptiveCard(body=body, actions=[submit])
        quantity_column = Column(items=quantity_column_items)
        item_column = Column(items=item_column_items)
        table = ColumnSet(columns=[quantity_column, item_column])
        body.append(table)
        # Create attachment
        attachment = {
            'contentType': 'application/vnd.microsoft.card.adaptive',
            'content': card.to_dict()
        }
        data_value = attachment['content']['actions'][0]['data'] = 'Confirm'

        return attachment
Exemplo n.º 13
0
    def generate_add_response():
        title = Container(items=[
            TextBlock(text=f"Currently adding a new switch",
                      size="Small",
                      weight="Lighter"),
        ])

        items = []
        for attr in vars(models.Switch).keys():
            # Don't append null values or internal attributes
            if attr[0] != '_':
                # This is so stupid, probably not the best way to do it
                target_type = str(
                    getattr(models.Switch, attr).property.columns[0].type)
                if target_type == "BOOLEAN":
                    items.append(Toggle(attr, attr))
                else:
                    items.append(TextBlock(text=f"{attr}"))
                    items.append(Text(attr, placeholder=f"{attr}"))

        submit = Submit(title="Add")

        body = Container(items=items)

        card = AdaptiveCard(
            body=[title, body],
            actions=[submit],
            fallbackText=str(
                "Adaptive cards need to be enabled to use this feature."))

        attachment = {
            "contentType": "application/vnd.microsoft.card.adaptive",
            "content": card.to_dict(),
        }

        return attachment
Exemplo n.º 14
0
def generate_teams_payload(adaptive_card: AdaptiveCard) -> dict:
    """Generate payload for MS Teams.

    Args:
        adaptive_card (AdaptiveCard): AdaptiveCard to generate payload with.

    Returns:
        dict: Payload dict for MS Teams.
    """

    # Add adaptive card to payload
    payload = {
        "type":
        "message",
        "attachments": [{
            "contentType": "application/vnd.microsoft.card.adaptive",
            "contentUrl": "null",
            "content": adaptive_card.to_dict(),
        }],
    }

    return payload
Exemplo n.º 15
0
def get_menu_card():
    greeting = TextBlock("Hi there, pick your action")

    choice_list = []
    choice_list.append({'title': 'List Pull requests', 'value': 'pr_list'})
    choice_list.append({
        'title': 'List code review requests',
        'value': 'cr_list'
    })
    choice_list.append({
        'title': 'Fetch PR check status',
        'value': 'pr_details'
    })
    choice_list.append({
        'title': 'Search for git/github issues',
        'value': 'search'
    })
    choice_list.append({'title': 'Open support request', 'value': 'support'})
    menu = Choices(id='choice', separator=True, choices=choice_list)

    submit = Submit(title="Submit")

    return AdaptiveCard(body=[greeting, menu], actions=[submit])
Exemplo n.º 16
0
def get_cr_list_output_card(userid, results):
    body = []
    body.append(
        TextBlock(f"Code reviews assigned to **{userid}**", isSubtle=True))

    repo = 'https://gh-xr.scm.engit.cisco.com/xr/iosxr'
    for r in results:
        pr_markdown = "[{n}]({r}/pull/{n})".format(n=r['number'], r=repo)
        number = Column([
            TextBlock(pr_markdown,
                      weight='bold',
                      horizontalAlignment=HorizontalAlignment.LEFT),
        ],
                        separator=True,
                        width='100px')
        title = Column([
            TextBlock(r['title'],
                      weight='bold',
                      horizontalAlignment=HorizontalAlignment.LEFT),
        ],
                       separator=True,
                       width='500px')
        author = Column([
            TextBlock(f"` {r['author']} `",
                      horizontalAlignment=HorizontalAlignment.LEFT),
        ],
                        separator=True,
                        width='150px')

        container = Container([
            ColumnSet([number, title, author]),
        ],
                              separator=True,
                              spacing=Spacing.MEDIUM)
        body.append(container)

    return AdaptiveCard(body=body)
Exemplo n.º 17
0
def get_pr_details_output_card(pr_number, results):
    body = []
    repo = 'https://gh-xr.scm.engit.cisco.com/xr/iosxr'
    if results:
        pr_markdown = "[{n}]({r}/pull/{n})".format(n=pr_number, r=repo)
        number = Column([
            TextBlock(pr_markdown,
                      weight='bold',
                      horizontalAlignment=HorizontalAlignment.LEFT),
        ],
                        separator=True,
                        width='60px')
        summary = Column([
            TextBlock(results['summary'],
                      horizontalAlignment=HorizontalAlignment.LEFT),
        ],
                         separator=True,
                         width='500px')
        body.append(Container([ColumnSet([number, summary])]))

        facts = []
        for i in results["checks"]:
            name = i['name']
            if i["status"] == 'success':
                value = '✔'
            elif i["status"] == 'failure':
                value = '✘'
            else:
                value = f'`{i["status"]}`'
            facts.append(Fact(name, value))
        # for
        body.append(FactSet(facts))
    else:
        body.append(TextBlock(f'No details found for {pr_number}'))

    return AdaptiveCard(body=body)
Exemplo n.º 18
0
def _generate_adaptive_card(
    top_articles: List[Page],
    articles_above_threshold: int,
    threshold: int = 10000,
) -> AdaptiveCard:

    # Generate intro
    greeting = random.choice(GREETINGS)
    intro_headline = TextBlock(
        "🎉 Unsere SEO-Highlights von gestern",
        weight="bolder",
        size="large",
        wrap=True,
    )
    intro_text = TextBlock(
        f"{greeting} Das sind die {len(top_articles)} Beiträge, mit denen wir gestern die meisten Besucher:innen von Google in unser Angebot locken konnten. **Können wir daraus was lernen?**",
        wrap=True,
    )
    intro = Container([intro_headline, intro_text])

    # Generate sections for each page
    article_sections = []

    for i, page in enumerate(top_articles):
        article_section = _generate_article_section(page, i)

        # Add separators between stories
        if i > 0:
            article_section.separator = True

        article_sections.append(article_section)

    # Generate above_threshold message (only if the threshold was passed)
    threshold = format_number(ARTICLE_THRESHOLD)
    above_threshold = TextBlock(
        text=
        f"Gestern hatten wir {articles_above_threshold} Beiträge mit mehr als {threshold} Klicks!",
        spacing="extralarge",
        size="medium",
        weight="bolder",
        wrap=True,
    )

    if articles_above_threshold > 3:
        above_threshold.text += " 🎉"
        above_threshold.size = "large"
    elif articles_above_threshold == 1:
        above_threshold.text = (
            f"Gestern hatten wir einen Beitrag mit mehr als {threshold} Klicks."
        )
        above_threshold.size = None
        above_threshold.weight = None
    elif articles_above_threshold < 1:
        above_threshold = None

    if above_threshold:
        article_sections.append(above_threshold)

    # Add note about GSC data
    note_gsc = Container(
        [
            TextBlock(
                text=("Letzter Datenabgleich mit der GSC: 15:30 Uhr"),
                spacing="None",
                wrap=True,
            ),
            TextBlock(
                text=
                ("Es dauert bis zu 48 Stunden, bis die Daten in der GSC final sind!"
                 ),
                spacing="Small",
                wrap=True,
            ),
        ],
        spacing="extralarge",
    )

    # Generate outro
    outro = TextBlock(
        text=f"[Infos zur Datenerhebung]({MORE_URL})",
        horizontalAlignment="right",
        spacing="large",
    )

    # Put everything together
    adaptive_card_body = [intro, *article_sections, note_gsc, outro]
    card = AdaptiveCard(body=adaptive_card_body)

    return card
Exemplo n.º 19
0
def create_update_instance_tag_card(tags, instanceid):

    _greeting = TextBlock(
        f"New EC2 Instance ID: {str(instanceid)}  "
        f"Has Been Created Please Validate Your Tags",
        horizontalAlignment=HorizontalAlignment.CENTER,
        size=FontSize.SMALL)

    _choices = [
        Choice("Cisco Restricted", "Cisco Restricted"),
        Choice("Cisco Highly Confidentia", "Cisco Highly Confidentia")
    ]
    _data_classification = Choices(id="Data Classification",
                                   choices=_choices,
                                   value=str(tags.dataclassification),
                                   style=2)

    _choices = [
        Choice("dev", "dev"),
        Choice("test", "test"),
        Choice("stage", "stage"),
        Choice("prod", "prod")
    ]
    _environment = Choices(id="Environment",
                           choices=_choices,
                           value=str(tags.environment),
                           style=2)

    _resourc_oewner = Text('Resource Owner', value=str(tags.resourceowner))

    _cisco_mail_alias = Text("Cisco Mail Alias",
                             value=str(tags.ciscomailalias))

    _choices = [Choice("Cisco Operations Data", "Cisco Operations Data")]
    _data_taxonomy = Choices(id="Data Taxonomy",
                             choices=_choices,
                             value=str(tags.datataxonomy),
                             style=2)

    _app_name = Text("Application Name", value=str(tags.appname))

    _footer = TextBlock(
        "Security Tags must be validated with in 24 hours "
        "or your EC2 instace will be terminated",
        horizontalAlignment=HorizontalAlignment.CENTER,
        size=FontSize.SMALL,
        color=Colors.ATTENTION)

    submit = Submit(title="Update", data={"instid": instanceid})
    card = AdaptiveCard(body=[
        _greeting, _app_name, _resourc_oewner, _cisco_mail_alias, _environment,
        _data_classification, _data_taxonomy, _footer
    ],
                        actions=[submit])
    attachment = {
        "contentType": CONTENT_TYPE,
        "content": card.to_dict(),
    }

    print(card.to_json(pretty=True))
    return attachment
Exemplo n.º 20
0
def get_cr_list_input_card():
    greeting = TextBlock("Enter <user-id> for PR reviewer lookup")
    user_id = Text('cr_list.user_id', placeholder="...")
    submit = Submit(title="Search")

    return AdaptiveCard(body=[greeting, user_id], actions=[submit])
Exemplo n.º 21
0
def _generate_adaptive_card(pages: Page,
                            last_update_gsc: str = None) -> AdaptiveCard:

    # Convert PDT timezone to Berlin time, because GSC-times are all PDT-based
    PDT = dt.timezone(-dt.timedelta(hours=7))
    yesterday = local_yesterday()
    start_time = dt.datetime(yesterday.year,
                             yesterday.month,
                             yesterday.day,
                             tzinfo=PDT)
    start_time_local = start_time.astimezone(BERLIN)

    # Generate intro
    greeting = random.choice(GREETINGS)
    intro = TextBlock(
        (f"{greeting} Diese Beiträge von uns sind seit gestern, {start_time_local.hour}:00 Uhr, "
         "mit Google gut gefunden worden und haben heute noch kein Update bekommen. "
         "**Lohnt sich eine Aktualisierung oder ein Weiterdreh?**"),
        wrap=True,
    )

    # Add note about GSC data
    note_gsc = Container(
        [
            TextBlock(
                text=(
                    f"Letzter Datenabgleich mit der GSC: {last_update_gsc} Uhr"
                ),
                spacing="None",
                wrap=True,
            ),
            TextBlock(
                text=
                ("Es dauert bis zu 48 Stunden, bis die Daten in der GSC final sind!"
                 ),
                spacing="Small",
                wrap=True,
            ),
        ],
        spacing="extralarge",
    )

    # Generate outro
    outro = TextBlock(
        text=f"[Infos zur Datenerhebung]({MORE_URL})",
        horizontalAlignment="right",
        spacing="large",
    )

    # Generate sections for each page
    stories = []

    for i, page in enumerate(pages):
        story = _generate_story(page)

        # Add separators between stories
        if i > 0:
            story.separator = True

        stories.append(story)

    # Put everything together
    adaptive_card_body = [intro, *stories, note_gsc, outro]
    card = AdaptiveCard(body=adaptive_card_body)

    return card
Exemplo n.º 22
0
from pyadaptivecards.actions import Submit
from pyadaptivecards.card import AdaptiveCard
from pyadaptivecards.components import TextBlock
from pyadaptivecards.inputs import Number, Text
from webexteamssdk import WebexTeamsAPI
import json

greeting = TextBlock("Hey hello there! I am a adaptive card")
first_name = Text('first_name', placeholder="First Name")
age = Number('age', placeholder="Age")

submit = Submit(title="Send me!")

card = AdaptiveCard(body=[greeting, first_name, age], actions=[submit])

with open("subscription.json") as file:
    active = json.load(file)
    
# Create a webex teams api connection
api = WebexTeamsAPI(access_token='MmM1ZTZlYmItZWI4Zi00NzgyLTgxYzctN2E5MDYyMTNhNzJmYTNkMjQ3OGYtM2Ex_PF84_1eb65fdf-9643-417f-9974-ad72cae0e10f')
room_id = "Y2lzY29zcGFyazovL3VzL1JPT00vMWNiYWMyN2ItNjEwYi0zNjBkLThhMTMtNjYzYTIxYjFlOTA2"
# Create a dict that will contain the card as well as some meta information
attachment = {
    "contentType": "application/vnd.microsoft.card.adaptive",
    "content": active,
}
api.messages.create(roomId=room_id, text="Fallback", attachments=[attachment])
Exemplo n.º 23
0
def get_pr_details_input_card():
    greeting = TextBlock("Enter PR number")
    number = Number('pr_details.pr_number', placeholder='12345')
    submit = Submit(title="Fetch")

    return AdaptiveCard(body=[greeting, number], actions=[submit])
Exemplo n.º 24
0
def get_search_input_card():
    greeting = TextBlock("Enter you search string w.r.to git/github")
    query = Text('query_string', placeholder="...")
    submit = Submit(title="Search")

    return AdaptiveCard(body=[greeting, query], actions=[submit])