summaryrefslogtreecommitdiff
path: root/src/modules/updates.tsx
blob: 0a8cbea39f4e88f97ebed548bd3d05c46eaf4873 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import { bind, execAsync, Variable } from "astal";
import { App, Astal, Gtk } from "astal/gtk3";
import Updates, { Repo as IRepo, Update as IUpdate } from "../services/updates";
import { MenuItem } from "../utils/widgets";
import PopupWindow from "../widgets/popupwindow";

const constructItem = (label: string, exec: string, quiet = true) =>
    new MenuItem({
        label,
        onActivate() {
            App.get_window("updates")?.hide();
            execAsync(exec).catch(e => !quiet && console.error(e));
        },
    });

const Update = (update: IUpdate) => {
    const menu = new Gtk.Menu();
    menu.append(constructItem("Open info in browser", `xdg-open '${update.url}'`, false));
    menu.append(constructItem("Open info in terminal", `uwsm app -- foot -H pacman -Qi ${update.name}`));
    menu.append(constructItem("Reinstall", `uwsm app -T -- yay -S ${update.name}`));
    menu.append(constructItem("Remove with dependencies", `uwsm app -T -- yay -Rns ${update.name}`));

    return (
        <button
            onClick={(_, event) => event.button === Astal.MouseButton.SECONDARY && menu.popup_at_pointer(null)}
            onDestroy={() => menu.destroy()}
        >
            <label
                truncate
                xalign={0}
                label={`${update.name} (${update.version.old} -> ${update.version.new})\n    ${update.description}`}
            />
        </button>
    );
};

const Repo = (repo: IRepo) => {
    const expanded = Variable(false);

    return (
        <box vertical className="repo">
            <button className="wrapper" cursor="pointer" onClicked={() => expanded.set(!expanded.get())}>
                <box className="header">
                    <label className="icon" label={repo.icon} />
                    <label label={`${repo.name} (${repo.updates.length})`} />
                    <box hexpand />
                    <label className="icon" label={bind(expanded).as(e => (e ? "expand_less" : "expand_more"))} />
                </box>
            </button>
            <revealer
                revealChild={bind(expanded)}
                transitionType={Gtk.RevealerTransitionType.SLIDE_DOWN}
                transitionDuration={200}
            >
                <box vertical className="list">
                    {repo.updates.map(Update)}
                </box>
            </revealer>
        </box>
    );
};

const List = () => (
    <box vertical valign={Gtk.Align.START} className="repos">
        {bind(Updates.get_default(), "updateData").as(d => d.repos.map(Repo))}
    </box>
);

export default () => (
    <PopupWindow name="updates">
        <box vertical className="updates">
            <box className="header">
                <label label={bind(Updates.get_default(), "numUpdates").as(n => `${n} update${n === 1 ? "" : "s"}`)} />
                <box hexpand />
                <button
                    cursor="pointer"
                    onClicked={() =>
                        execAsync("uwsm app -T -- yay")
                            .then(() => Updates.get_default().getUpdates())
                            // Ignore errors
                            .catch(() => {})
                    }
                    label="Update all"
                />
                <button cursor="pointer" onClicked={() => Updates.get_default().getUpdates()} label="Reload" />
            </box>
            <stack
                transitionType={Gtk.StackTransitionType.CROSSFADE}
                transitionDuration={150}
                shown={bind(Updates.get_default(), "numUpdates").as(n => (n > 0 ? "list" : "empty"))}
            >
                <box vertical valign={Gtk.Align.CENTER} name="empty">
                    <label className="icon" label="deployed_code_history" />
                    <label label="All packages up to date!" />
                </box>
                <scrollable expand hscroll={Gtk.PolicyType.NEVER} name="list">
                    <List />
                </scrollable>
            </stack>
        </box>
    </PopupWindow>
);