Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Updated to podman 2.0.3 json format #14

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,23 @@ See the [gnome extensions page](https://extensions.gnome.org/extension/1500/cont

# Install from source

First pick the right branch by the gnome-shell-X.XX version:
First pick the right branch by the `gnome-shell-X.XX` version:

| branch | gnome-shell version |
| --- | --- |
| master | 3.36.1 |
| 3.36 | 3.36.4 |
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The podman version is something that needs handling as well. I'm thinking on adding per podman release json parsing handling. Some people may newer version of gnome but old podman versions and vice versa.

| 3.34.2 | 3.34.2 |
| 3.28.3 | 3.28.3 |


Clone, Pack, and Install

```console
$ git clone https://github.com/rgolangh/gnome-shell-extension-containers
$ make all
```

Or using 'Tweaks' -> Extensions -> toggle 'Containers'
Or using 'Tweaks' -> Extensions -> toggle 'Containers':

<p>
<img src="screenshot.png" width="350" title="gnome-shell-extension-containers">
Expand Down
279 changes: 148 additions & 131 deletions extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,22 +48,22 @@ var ContainersMenu = GObject.registerClass(
{
GTypeName: 'ContainersMenu'
},
class ContainersMenu extends PanelMenu.Button {
_init() {
super._init(0.0, "Containers");
this.menu.box.add_style_class_name('containers-extension-menu');
const hbox = new St.BoxLayout({ style_class: 'panel-status-menu-box' });
const gicon = Gio.icon_new_for_string(Me.path + "/podman-icon.png");
const icon = new St.Icon({ gicon: gicon, icon_size: '24' });
class ContainersMenu extends PanelMenu.Button {
_init() {
super._init(0.0, "Containers");
this.menu.box.add_style_class_name('containers-extension-menu');
const hbox = new St.BoxLayout({ style_class: 'panel-status-menu-box' });
const gicon = Gio.icon_new_for_string(Me.path + "/podman-icon.png");
const icon = new St.Icon({ gicon: gicon, icon_size: '24' });

hbox.add_child(icon);
hbox.add_child(PopupMenu.arrowIcon(St.Side.BOTTOM));
this.add_child(hbox);
this.connect('button_press_event', Lang.bind(this, () => {
if (this.menu.isOpen) {
this.menu.removeAll();
this.renderMenu();
}
hbox.add_child(icon);
hbox.add_child(PopupMenu.arrowIcon(St.Side.BOTTOM));
this.add_child(hbox);
this.connect('button_press_event', Lang.bind(this, () => {
if (this.menu.isOpen) {
this.menu.removeAll();
this.renderMenu();
}
}));
}

Expand All @@ -73,37 +73,40 @@ class ContainersMenu extends PanelMenu.Button {
info(`found ${containers.length} containers`);
if (containers.length > 0) {
containers.forEach((container) => {
debug(container);
const subMenu = new ContainerSubMenuMenuItem(container, container.Names);
debug(`Menu item for container ${container.Id} with name ${container.Names[0]}`);
const subMenu = new ContainerSubMenuMenuItem(container, container.Names[0]);
this.menu.addMenuItem(subMenu);
});
} else {
this.menu.addMenuItem(new PopupMenu.PopupMenuItem("No containers detected"));
}
} catch (err) {
const errMsg = _("Error occurred when fetching containers");
const errMsg = _("Error occurred when rendering containers");
this.menu.addMenuItem(new PopupMenu.PopupMenuItem(errMsg));
info(`${errMsg}: ${err}`);
}
this.show();
}
});


/* getContainers return a json array containers in the form of
[
{
"ID": "7a9e1233db51",
"Id": "7a9e1233db51",
"Image": "localhost/image-name:latest",
"Command": "/entrypoint.sh bash",
"CreatedAtTime": "2018-10-10T10:14:47.884563227+03:00",
"Created": "2 weeks ago",
"Status": "Created",
"Ports": "",
"Created": "1596032658",
"CreatedAt": "2 weeks ago",
"State": "stopped",
"Ports": [],
"Size": "",
"Names": "sleepy_shockley",
"Labels": "key=value,"
},
"Names": [
"sleepy_shockley"
],
"Labels": {
"key": "value"
}
}
]
*/
const getContainers = () => {
Expand Down Expand Up @@ -156,132 +159,141 @@ var PopupMenuItem = GObject.registerClass(
{
GTypeName: 'PopupMenuItem'
},
class extends PopupMenu.PopupMenuItem {
_init(label, value) {
if (value === undefined) {
super._init(label);
} else {
super._init(`${label}: ${value}`);
this.connect('button_press_event', Lang.bind(this, () => {
setClipboard(value);
}, false));
class extends PopupMenu.PopupMenuItem {
_init(label, value) {
if (value === undefined) {
super._init(label);
} else {
super._init(`${label}: ${value}`);
this.connect('button_press_event', Lang.bind(this, () => {
setClipboard(value);
}, false));
}
this.add_style_class_name("containers-extension-subMenuItem");
}
this.add_style_class_name("containers-extension-subMenuItem");
}
});
);

var ContainerMenuItem = GObject.registerClass(
{
GTypeName: 'ContainerMenuItem'
},
class extends PopupMenuItem {
_init(containerName, command) {
super._init(command);
this.containerName = containerName;
this.command = command;
this.connect('activate', Lang.bind(this, () => {
runCommand(this.command, this.containerName);
}));
class extends PopupMenuItem {
_init(containerName, command) {
super._init(command);
this.containerName = containerName;
this.command = command;
this.connect('activate', Lang.bind(this, () => {
runCommand(this.command, this.containerName);
}));
}
}
});
);

var ContainerMenuWithOutputItem = GObject.registerClass(
{
{
GTypeName: 'ContainerMenuWithOutputItem'
},
class extends PopupMenuItem {
_init(containerName, command, outputHdndler) {
super._init(command);
this.containerName = containerName;
this.command = command;
this.connect('activate', Lang.bind(this, () => {
var out = runCommand(this.command, this.containerName);
outputHdndler(out);
}));
},
class extends PopupMenuItem {
_init(containerName, command, outputHdndler) {
super._init(command);
this.containerName = containerName;
this.command = command;
this.connect('activate', Lang.bind(this, () => {
var out = runCommand(this.command, this.containerName);
outputHdndler(out);
}));
}
}
});
);

var ContainerMenuItemWithTerminalAction = GObject.registerClass(
{
{
GTypeName: 'ContainerMenuItemWithTerminalAction'
},
class extends PopupMenuItem {
_init(label, containerName, command, args) {
super._init(label);
this.containerName = containerName;
this.command = command;
this.args = args;
this.connect('activate', Lang.bind(this, () => {
runCommandInTerminal(this.command, this.containerName, this.args);
}));
},
class extends PopupMenuItem {
_init(label, containerName, command, args) {
super._init(label);
this.containerName = containerName;
this.command = command;
this.args = args;
this.connect('activate', Lang.bind(this, () => {
runCommandInTerminal(this.command, this.containerName, this.args);
}));
}
}
});

);

var ContainerSubMenuMenuItem = GObject.registerClass(
{
GTypeName: 'ContainerSubMenuMenuItem'
},
class extends PopupMenu.PopupSubMenuMenuItem {
_init(container, name) {
super._init(container.Names);
this.menu.addMenuItem(new PopupMenuItem("Status", container.Status));
this.menu.addMenuItem(new PopupMenuItem("Id", container.ID));
this.menu.addMenuItem(new PopupMenuItem("Image", container.Image));
this.menu.addMenuItem(new PopupMenuItem("Command", container.Command));
this.menu.addMenuItem(new PopupMenuItem("Created", container.Created));
this.menu.addMenuItem(new PopupMenuItem("Ports", container.Ports));
class extends PopupMenu.PopupSubMenuMenuItem {
_init(container, name) {
super._init(container.Names[0]);
this.menu.addMenuItem(new PopupMenuItem("Status", container.State));
this.menu.addMenuItem(new PopupMenuItem("Id", container.Id));
this.menu.addMenuItem(new PopupMenuItem("Image", container.Image));
this.menu.addMenuItem(new PopupMenuItem("Command", container.Command));
this.menu.addMenuItem(new PopupMenuItem("Created", timeConverter(container.Created)));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can actually just use CreatedAt

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

this.menu.addMenuItem(new PopupMenuItem("Ports", container.Ports));

// add more stats and info - inspect - SLOW
this.connect("button_press_event", Lang.bind(this, () => {
inspect(container.Names, this.menu);
}));
// end of inspect
// add more stats and info - inspect - SLOW
this.connect("button_press_event", Lang.bind(this, () => {
debug(`Inspect ${container.Names[0]}`)
inspect(container.Names[0], this.menu);
}));
// end of inspect

switch (container.Status.split(" ")[0]) {
case "Exited":
case "Created":
case "stopped":
debug(`Eval container ${container.Names[0]} state ${container.State}`)

this.insert_child_at_index(createIcon('process-stop-symbolic', 'status-stopped'), 1);
const startMeunItem = new ContainerMenuItem(container.Names, "start");
startMeunItem.insert_child_at_index(createIcon('media-playback-start-symbolic', 'status-start'), 1);
this.menu.addMenuItem(startMeunItem);
const rmMenuItem = new ContainerMenuItem(container.Names, "rm");
rmMenuItem.insert_child_at_index(createIcon('user-trash-symbolic', 'status-remove'), 1);
this.menu.addMenuItem(rmMenuItem);
break;
case "Up":
this.insert_child_at_index(createIcon('media-playback-start-symbolic', 'status-running'), 1);
const pauseMenuIten = new ContainerMenuItem(container.Names, "pause");
pauseMenuIten.insert_child_at_index(createIcon('media-playback-pause-symbolic', 'status-stopped'), 1);
this.menu.addMenuItem(pauseMenuIten);
const stopMenuItem = new ContainerMenuItem(container.Names, "stop");
stopMenuItem.insert_child_at_index(createIcon('process-stop-symbolic', 'status-stopped'), 1);
this.menu.addMenuItem(stopMenuItem);
const restartMenuItem = new ContainerMenuItem(container.Names, "restart");
restartMenuItem.insert_child_at_index(createIcon('system-reboot-symbolic', 'status-restart'), 1);
this.menu.addMenuItem(restartMenuItem);
this.menu.addMenuItem(createTopMenuItem(container));
this.menu.addMenuItem(createShellMenuItem(container));
this.menu.addMenuItem(createStatsMenuItem(container));
break;
case "Paused":
this.insert_child_at_index(createIcon('media-playback-pause-symbolic', 'status-paused'), 1);
const unpauseMenuItem = new ContainerMenuItem(container.Names, "unpause");
unpauseMenuItem.insert_child_at_index(createIcon('media-playback-start-symbolic', 'status-start'), 1)
this.menu.addMenuItem(unpauseMenuItem);
break;
default:
this.insert_child_at_index(createIcon('action-unavailable-symbolic', 'status-undefined'), 1);
break;
}
switch (container.State) {
case "exited":
case "created":
case "stopped":
this.insert_child_at_index(createIcon('process-stop-symbolic', 'status-stopped'), 1);
const startMeunItem = new ContainerMenuItem(container.Names[0], "start");
startMeunItem.insert_child_at_index(createIcon('media-playback-start-symbolic', 'status-start'), 1);
this.menu.addMenuItem(startMeunItem);
const rmMenuItem = new ContainerMenuItem(container.Names[0], "rm");
rmMenuItem.insert_child_at_index(createIcon('user-trash-symbolic', 'status-remove'), 1);
this.menu.addMenuItem(rmMenuItem);
break;

case "running":
this.insert_child_at_index(createIcon('media-playback-start-symbolic', 'status-running'), 1);
const pauseMenuIten = new ContainerMenuItem(container.Names[0], "pause");
pauseMenuIten.insert_child_at_index(createIcon('media-playback-pause-symbolic', 'status-stopped'), 1);
this.menu.addMenuItem(pauseMenuIten);
const stopMenuItem = new ContainerMenuItem(container.Names[0], "stop");
stopMenuItem.insert_child_at_index(createIcon('process-stop-symbolic', 'status-stopped'), 1);
this.menu.addMenuItem(stopMenuItem);
const restartMenuItem = new ContainerMenuItem(container.Names[0], "restart");
restartMenuItem.insert_child_at_index(createIcon('system-reboot-symbolic', 'status-restart'), 1);
this.menu.addMenuItem(restartMenuItem);
this.menu.addMenuItem(createTopMenuItem(container));
this.menu.addMenuItem(createShellMenuItem(container));
this.menu.addMenuItem(createStatsMenuItem(container));
break;

case "paused":
this.insert_child_at_index(createIcon('media-playback-pause-symbolic', 'status-paused'), 1);
const unpauseMenuItem = new ContainerMenuItem(container.Names[0], "unpause");
unpauseMenuItem.insert_child_at_index(createIcon('media-playback-start-symbolic', 'status-start'), 1)
this.menu.addMenuItem(unpauseMenuItem);
break;

default:
this.insert_child_at_index(createIcon('action-unavailable-symbolic', 'status-undefined'), 1);
break;
}

// add log button
const logMenuItem = createLogMenuItem(container);
this.menu.addMenuItem(logMenuItem);
// add log button
const logMenuItem = createLogMenuItem(container);
this.menu.addMenuItem(logMenuItem);
}
}
});
);

function setClipboard(text) {
St.Clipboard.get_default().set_text(St.ClipboardType.PRIMARY, text);
Expand All @@ -297,26 +309,31 @@ function inspect(container, menu) {
}

function createLogMenuItem(container) {
let i = new ContainerMenuItemWithTerminalAction("logs", "", `podman logs -f ${container.Names}`, "");
let i = new ContainerMenuItemWithTerminalAction("logs", "", `podman logs -f ${container.Names[0]}`, "");
i.insert_child_at_index(createIcon('document-open-symbolic.symbolic', 'action-logs'), 1)
return i
}

function createTopMenuItem(container) {
const i = new ContainerMenuItemWithTerminalAction("top", container.Names, "watch podman top", "");
const i = new ContainerMenuItemWithTerminalAction("top", container.Names[0], "watch podman top", "");
i.insert_child_at_index(createIcon('view-reveal-symbolic.symbolic', 'action-top'), 1);
return i;
}

function createShellMenuItem(container) {
const i = new ContainerMenuItemWithTerminalAction("sh", container.Names, "podman exec -it", "/bin/sh");
const i = new ContainerMenuItemWithTerminalAction("sh", container.Names[0], "podman exec -it", "/bin/sh");
i.insert_child_at_index(new St.Label({ style_class: 'action-sh', text: ">_" }), 1);
return i;
}

function createStatsMenuItem(container) {
const i = new ContainerMenuItemWithTerminalAction("stats", container.Names, "podman stats", "");
const i = new ContainerMenuItemWithTerminalAction("stats", container.Names[0], "podman stats", "");
i.insert_child_at_index(new St.Label({ style_class: 'action-stats', text: "%" }), 1);
return i;
}

function timeConverter(UNIX_timestamp) {
var dateObject = new Date(UNIX_timestamp * 1000);

return dateObject.toLocaleString()
}