gpouilloux / gnome-shell-extension-docker

An extension for managing docker containers
GNU General Public License v3.0
146 stars 71 forks source link

[REQUEST] Remove indicator icon from status when there are no containers #30

Open eyalch opened 6 years ago

eyalch commented 6 years ago

Since there's no functionality when there are no containers, could we please have an option to remove the icon from the status bar when in such condition?

webmastak commented 5 years ago

In the src/dockerMenu.js file, in fact, partially. If we delete the last container and click on the extension icon, the icon is hidden. When launching a new container, then you need Alt + F2 to restart the shell so that the icon appears again.

'use strict';

const St = imports.gi.St;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const DockerSubMenuMenuItem = Me.imports.src.dockerSubMenuMenuItem;
const DockerMenuStatusItem = Me.imports.src.dockerMenuStatusItem;

// Docker icon on status menu
const DockerMenu = new Lang.Class({
    Name: 'DockerMenu.DockerMenu',
    Extends: PanelMenu.Button,

    // Init the docker menu
    _init: function() {
        this.parent(0.0, _("Docker containers"));
        let hbox = new St.BoxLayout({ style_class: 'panel-status-menu-box' }); 
        let gicon = Gio.icon_new_for_string(Me.path + "/docker.svg");
        let dockerIcon = new St.Icon({ gicon: gicon, icon_size: '24'});
        hbox.add_child(dockerIcon);
        hbox.add_child(PopupMenu.arrowIcon(St.Side.BOTTOM));
        this.actor.add_child(hbox);
        this.actor.connect('button_press_event', Lang.bind(this, this._refreshMenu));
        this._renderMenu(); 
        this._indicatorHide();            
    },

    // Refresh  the menu everytime the user click on it
    // It allows to have up-to-date information on docker containers
    _refreshMenu: function() {
        if(this.menu.isOpen) {
            this.menu.removeAll();
            this._renderMenu();
            this._indicatorHide();
        }
    },

    // Checks if docker is installed on the host machine
    _isDockerInstalled: function() {
        return GLib.find_program_in_path('docker') != undefined;
    },

    // Checks if the docker daemon is running or not
    _isDockerRunning: function() {
        let [res, pid, in_fd, out_fd, err_fd] = GLib.spawn_async_with_pipes(null, ['/bin/ps', 'cax'], null, 0, null);

        let out_reader = new Gio.DataInputStream({
          base_stream: new Gio.UnixInputStream({fd: out_fd})
        });

        // Look for the docker process running
        let dockerRunning = false;
        let hasLine = true;
        do {
            let [out, size] = out_reader.read_line(null);
            if(out != null && out.toString().indexOf("docker") > -1) {
                dockerRunning = true;
            } else if(size <= 0) {
                hasLine = false;
            }

        } while(!dockerRunning && hasLine);

        return dockerRunning;
    },

    // Show docker menu icon only if installed and append docker containers
    _renderMenu: function() {
        if(this._isDockerInstalled()) {
          if(this._isDockerRunning()) {
              this._feedMenu();
          } else {
              let errMsg = _("Докер не запущен");
              this.menu.addMenuItem(new PopupMenu.PopupMenuItem(errMsg));
              log(errMsg);
          }

          // Add Turn On / Turn Off Switch always
          let statusSwitch = new DockerMenuStatusItem.DockerMenuStatusItem('Статус докера');
          this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
          this.menu.addMenuItem(statusSwitch);
        } else {
          let errMsg = _("Двоичный файл докера не найден в PATH");
          this.menu.addMenuItem(new PopupMenu.PopupMenuItem(errMsg));
          log(errMsg);
        }
        this.actor.show();
    },

    // Append containers to menu
    _feedMenu: function() {

        let delimiter = ',';
        let [res, out, err, status] = GLib.spawn_command_line_sync("docker ps -a --format '{{.Names}}" + delimiter + "{{.Status}}'");

        if(status == 0) {
            let outStr = String.fromCharCode.apply(String, out);
            let dockerContainers = outStr.split('\n');
            let numberContainers = dockerContainers.length-1;

            if (numberContainers) {
              // foreach container, add an entry in the menu
              for(let i = 0; i < numberContainers; i++) {
                  let [containerName, containerStatusMessage] = dockerContainers[i].split(delimiter);
                  let subMenu = new DockerSubMenuMenuItem.DockerSubMenuMenuItem(containerName, containerStatusMessage);
                  this.menu.addMenuItem(subMenu);
              }
            } 

        } else {
            let errMsg = "Ошибка при получении контейнеров";
            this.menu.addMenuItem(new PopupMenu.PopupMenuItem(errMsg));
            log(errMsg);
            log(err);
        }
    },

    // Docker hide indicator if there are no containers
   _indicatorHide() {
       let delimiter = ',';
       let [res, out, err, status] = GLib.spawn_command_line_sync("docker ps -a --format '{{.Names}}" + delimiter + "{{.Status}}'");
       if(status == 0) {
           let outStr = String.fromCharCode.apply(String, out);
           let dockerContainers = outStr.split('\n');
           let numberContainers = dockerContainers.length-1;
           if (numberContainers) {
           this.actor.visible = true; 
       } else {
           this.actor.visible = false;
       }
    } 
  }
});