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