mirror of
https://github.com/zulip/zulip.git
synced 2025-10-23 04:52:12 +00:00
zform: Convert module to typescript.
This commit is contained in:
@@ -54,7 +54,7 @@ Some important code entities for the widget implementation are:
|
||||
- `web/src/submessage.js`
|
||||
- `web/src/poll_widget.js`
|
||||
- `web/src/widgetize.ts`
|
||||
- `web/src/zform.js`
|
||||
- `web/src/zform.ts`
|
||||
- `web/templates/widgets/`
|
||||
- `zerver/lib/widget.py`
|
||||
- `zerver/views/submessage.py`
|
||||
@@ -308,7 +308,7 @@ widgets.todo = todo_widget;
|
||||
widgets.zform = zform;
|
||||
```
|
||||
|
||||
The code in `web/src/zform.js` renders the form (not
|
||||
The code in `web/src/zform.ts` renders the form (not
|
||||
shown here) and then sets up a click handler like below:
|
||||
|
||||
```js
|
||||
|
@@ -307,7 +307,7 @@ EXEMPT_FILES = make_set(
|
||||
"web/src/views_util.ts",
|
||||
"web/src/widget_modal.ts",
|
||||
"web/src/zcommand.ts",
|
||||
"web/src/zform.js",
|
||||
"web/src/zform.ts",
|
||||
"web/src/zulip_test.ts",
|
||||
# Test library code isn't always fully used.
|
||||
"web/tests/lib/example_user.cjs",
|
||||
|
@@ -12,20 +12,18 @@ import * as widgetize from "./widgetize.ts";
|
||||
|
||||
export type Submessage = z.infer<typeof message_store.submessage_schema>;
|
||||
|
||||
export const zform_widget_extra_data_schema = z.nullable(
|
||||
z.object({
|
||||
choices: z.array(
|
||||
z.object({
|
||||
type: z.string(),
|
||||
long_name: z.string(),
|
||||
reply: z.string(),
|
||||
short_name: z.string(),
|
||||
}),
|
||||
),
|
||||
heading: z.string(),
|
||||
type: z.literal("choices"),
|
||||
}),
|
||||
);
|
||||
export const zform_widget_extra_data_schema = z.object({
|
||||
choices: z.array(
|
||||
z.object({
|
||||
type: z.string(),
|
||||
long_name: z.string(),
|
||||
reply: z.string(),
|
||||
short_name: z.string(),
|
||||
}),
|
||||
),
|
||||
heading: z.string(),
|
||||
type: z.literal("choices"),
|
||||
});
|
||||
|
||||
const poll_widget_extra_data_schema = z.nullable(
|
||||
z.object({
|
||||
@@ -38,7 +36,10 @@ const widget_data_event_schema = z.object({
|
||||
sender_id: z.number(),
|
||||
data: z.discriminatedUnion("widget_type", [
|
||||
z.object({widget_type: z.literal("poll"), extra_data: poll_widget_extra_data_schema}),
|
||||
z.object({widget_type: z.literal("zform"), extra_data: zform_widget_extra_data_schema}),
|
||||
z.object({
|
||||
widget_type: z.literal("zform"),
|
||||
extra_data: z.nullable(zform_widget_extra_data_schema),
|
||||
}),
|
||||
z.object({
|
||||
widget_type: z.literal("todo"),
|
||||
extra_data: todo_widget_extra_data_schema,
|
||||
|
@@ -5,13 +5,7 @@ import * as message_lists from "./message_lists.ts";
|
||||
import type {Message} from "./message_store.ts";
|
||||
import type {Event, PollWidgetExtraData, PollWidgetOutboundData} from "./poll_widget.ts";
|
||||
import type {TodoWidgetExtraData, TodoWidgetOutboundData} from "./todo_widget.ts";
|
||||
|
||||
// TODO: This ZFormExtraData type should be moved to web/src/zform.js when it will be migrated
|
||||
type ZFormExtraData = {
|
||||
type: string;
|
||||
heading: string;
|
||||
choices: {type: string; reply: string; long_name: string; short_name: string}[];
|
||||
};
|
||||
import type {ZFormExtraData} from "./zform.ts";
|
||||
|
||||
type WidgetExtraData = PollWidgetExtraData | TodoWidgetExtraData | ZFormExtraData | null;
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import * as poll_widget from "./poll_widget.ts";
|
||||
import * as todo_widget from "./todo_widget.ts";
|
||||
import * as widgetize from "./widgetize.ts";
|
||||
import * as zform from "./zform.js";
|
||||
import * as zform from "./zform.ts";
|
||||
|
||||
export function initialize() {
|
||||
widgetize.widgets.set("poll", poll_widget);
|
||||
|
@@ -1,43 +1,51 @@
|
||||
import $ from "jquery";
|
||||
import type * as z from "zod/mini";
|
||||
|
||||
import render_widgets_zform_choices from "../templates/widgets/zform_choices.hbs";
|
||||
|
||||
import * as blueslip from "./blueslip.ts";
|
||||
import type {Message} from "./message_store.ts";
|
||||
import type {Event} from "./poll_widget.ts";
|
||||
import {zform_widget_extra_data_schema} from "./submessage.ts";
|
||||
import * as transmit from "./transmit.ts";
|
||||
|
||||
export function activate(opts) {
|
||||
const self = {};
|
||||
export type ZFormExtraData = z.infer<typeof zform_widget_extra_data_schema>;
|
||||
|
||||
export function activate(opts: {
|
||||
$elem: JQuery;
|
||||
extra_data: unknown;
|
||||
message: Message;
|
||||
}): {handle_events: (events: Event[]) => void} | undefined {
|
||||
const $outer_elem = opts.$elem;
|
||||
const parse_result = zform_widget_extra_data_schema.safeParse(opts.extra_data);
|
||||
|
||||
if (!parse_result.success) {
|
||||
blueslip.warn("invalid zform extra data", parse_result.error.issues);
|
||||
blueslip.warn("invalid zform extra data", {issues: parse_result.error.issues});
|
||||
return undefined;
|
||||
}
|
||||
const {data} = parse_result;
|
||||
|
||||
function make_choices(data) {
|
||||
function make_choices(data: ZFormExtraData): JQuery {
|
||||
// Assign idx values to each of our choices so that
|
||||
// our template can create data-idx values for our
|
||||
// JS code to use later.
|
||||
for (const [idx, choice] of data.choices.entries()) {
|
||||
choice.idx = idx;
|
||||
}
|
||||
const data_with_choices_with_idx = {
|
||||
...data,
|
||||
choices: data.choices.map((choice, idx) => ({...choice, idx})),
|
||||
};
|
||||
|
||||
const html = render_widgets_zform_choices(data);
|
||||
const html = render_widgets_zform_choices(data_with_choices_with_idx);
|
||||
const $elem = $(html);
|
||||
|
||||
$elem.find("button").on("click", (e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
// Grab our index from the markup.
|
||||
const idx = $(e.target).attr("data-idx");
|
||||
const idx = Number.parseInt($(e.target).attr("data-idx")!, 10);
|
||||
|
||||
// Use the index from the markup to dereference our
|
||||
// data structure.
|
||||
const reply_content = data.choices[idx].reply;
|
||||
const reply_content = data.choices[idx]!.reply;
|
||||
|
||||
transmit.reply_message(opts.message, reply_content);
|
||||
});
|
||||
@@ -45,16 +53,13 @@ export function activate(opts) {
|
||||
return $elem;
|
||||
}
|
||||
|
||||
function render() {
|
||||
let rendered_widget;
|
||||
|
||||
function render(): void {
|
||||
if (data.type === "choices") {
|
||||
rendered_widget = make_choices(data);
|
||||
$outer_elem.html(rendered_widget);
|
||||
$outer_elem.html(make_choices(data).html());
|
||||
}
|
||||
}
|
||||
|
||||
self.handle_events = function (events) {
|
||||
const handle_events = function (events: Event[]): void {
|
||||
if (events) {
|
||||
blueslip.info("unexpected");
|
||||
}
|
||||
@@ -63,5 +68,5 @@ export function activate(opts) {
|
||||
|
||||
render();
|
||||
|
||||
return self;
|
||||
return {handle_events};
|
||||
}
|
Reference in New Issue
Block a user