github.com/aitjcize/Overlord@v0.0.0-20240314041920-104a804cf5e8/overlord/app/common/js/BaseApp.jsx (about)

     1  // Copyright 2015 The Chromium OS Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style license that can be
     3  // found in the LICENSE file.
     4  //
     5  // Defines common functions of Apps.
     6  //
     7  // Automatically load clients from server in "compononetDidMount" event. The
     8  // client list is fetched from @this.props.url and will be stored in
     9  // @this.state.clients. But when rendering, you might want using
    10  // @this.getFilteredClientList to remove all clients that should be hidden.
    11  //
    12  // Example:
    13  //   var App = React.createClass({
    14  //     mixins: [BaseApp],
    15  //     getInitialState: function () {
    16  //       return {...addtional_states};
    17  //     },
    18  //     componentWillMount: function () {
    19  //       // You can register filters and handlers here.
    20  //       // See @addOnNewClientHandler, @addClientFilter
    21  //     },
    22  //     componentDidMount: function () {
    23  //       // loadClientsFromServer will be called after componentWillMount,
    24  //       // before this function. You can, for example, create sockets in this
    25  //       // method.
    26  //     },
    27  //     render: function () {
    28  //       var clients = this.getFilteredClientList();
    29  //       // render the UI using clients...
    30  //     }
    31  //   });
    32  
    33  var BaseApp = {
    34    // A machine id filter, this filter is added to @this.state.clientFilters by
    35    // default, you can use @this.setMidFilterPattern to set the pattern used to
    36    // filter clients.
    37    //
    38    // for example:
    39    //   var onKeyUp = function (event) {
    40    //     this.setMidFilterPattern(this.refs.filter.value);
    41    //   };
    42    //   <input type="text" ref="filter" onKeyUp={onKeyUp} />
    43    _clientMidFilter: function (client) {
    44      if (typeof(this.state.midPattern) == "undefined") {
    45        return true;
    46      }
    47      return this.state.midPattern.test(client.mid);
    48    },
    49    _clientDisplayFilter: function (client) {
    50      if (typeof(this.state.displayPattern) == "undefined") {
    51        return true;
    52      }
    53      return this.state.displayPattern.test(displayClient(client));
    54    },
    55    getInitialState: function () {
    56      this.onNewClientHandlers = [];
    57      return {
    58        clients: [],
    59        midPattern: undefined,
    60        displayPattern: undefined,
    61        clientFilters: [this._clientMidFilter, this._clientDisplayFilter]
    62      };
    63    },
    64    componentDidMount: function () {
    65      this.loadClientsFromServer();
    66    },
    67    // Get a list of clients from @this.props.url, "propperties" of each client
    68    // would also be fetched through /api/agent/properties/ API. Each client
    69    // would be added to @this.state.clients by invoking @this.addClient API.
    70    // Use @this.addOnNewClientHandler to prevent adding uninteresting clients.
    71    loadClientsFromServer: function () {
    72      $.ajax({
    73        url: this.props.url,
    74        dataType: "json",
    75        success: function (data) {
    76          for (var i = 0; i < data.length; i++) {
    77            this.addClient(data[i]);
    78          }
    79        }.bind(this),
    80        error: function (xhr, status, err) {
    81          console.error(this.props.url, status, err.toString());
    82        }.bind(this)
    83      });
    84    },
    85    // Get "properties" of a client (defined by machine id) from server.  For
    86    // details about "properties" attribute of a client, please see
    87    // FixtureWidget.
    88    fetchProperties: function (mid, callback) {
    89      var url = "/api/agent/properties/" + mid;
    90      $.ajax({
    91        url: url,
    92        dataType: "json",
    93        success: callback,
    94        error: function (xhr, status, err) {
    95          console.error(url, status, err.toString());
    96        }.bind(this)
    97      });
    98    },
    99    // Adds a client to @this.state.clients, will call @this.fetchProperties to
   100    // get "properties" attribute of the client.
   101    // Will pass the client to each onNewClientHandler, if any handler returns
   102    // false, the client won't be added.
   103    addClient: function (client) {
   104      if (this.isClientInList(this.state.clients, client)) {
   105        return;
   106      }
   107  
   108      // TODO(pihsun): Don't fetch the properties again if it's already in client.
   109      this.fetchProperties(client.mid, function (properties) {
   110        client.properties = properties;
   111  
   112        if (this.isClientInList(this.state.clients, client)) {
   113          return;
   114        }
   115  
   116        for (var i = 0; i < this.onNewClientHandlers.length; i++) {
   117          if (!this.onNewClientHandlers[i](client)) {
   118            return;
   119          }
   120        }
   121  
   122        this.setState(function (state, props) {
   123          state.clients.push(client);
   124          state.clients.sort(function (a, b) {
   125            return a.mid.localeCompare(b.mid);
   126          });
   127        });
   128      }.bind(this));
   129    },
   130    removeClient: function (data) {
   131      this.setState(function (state, props) {
   132        this.removeClientFromList(state.clients, data);
   133      });
   134    },
   135    // Add a hook to @this.addClient, when a client is going to be added to
   136    // @this.state.clients, handlers will be invoke to determine whether we
   137    // should abort the action or not, the client that is going to be added
   138    // would be passed to each handler, if any handler returns false, the
   139    // client won't be added. The client will have "properties" attribute.
   140    addOnNewClientHandler: function (callback) {
   141      if (this.onNewClientHandlers.indexOf(callback) === -1) {
   142        this.onNewClientHandlers.push(callback);
   143      }
   144    },
   145    // If a handler previously added by @this.addOnNewClientHandler is not an
   146    // anonymous function, you can use this function to remove it from the
   147    // list.
   148    removeOnNewClientHandler: function (callback) {
   149      var index = this.onNewClientHandlers.indexOf(callback);
   150      if (index !== -1) {
   151        this.onNewClientHandlers.splice(index, 1);
   152      }
   153    },
   154    // add a filter to determine which clients should not be shown, the
   155    // function @this.getFilteredClientList will pass each client to each
   156    // filter, if any filter returns false, that client will be filtered out.
   157    addClientFilter: function (filter) {
   158      this.setState(function (state, props) {
   159        if (state.clientFilters.indexOf(filter) === -1) {
   160          state.clientFilters.push(filter);
   161        }
   162      });
   163    },
   164    // If a filter previously added by @this.addClientFilter is not an
   165    // anonymous function, you can use this function to remove it from the
   166    // list.
   167    removeClientFilter: function (filter) {
   168      var index = this.state.clientFilters.indexOf(filter);
   169      if (index !== -1) {
   170        this.state.clientFilters.splice(index, 1);
   171      }
   172    },
   173    // Pass each element in @this.state.clients to each filter registered by
   174    // @this.addClientFilter, if any filter returns false, that client will not
   175    // be returned.
   176    getFilteredClientList: function () {
   177      var filteredList = this.state.clients.slice();
   178      for (var i = 0; i < this.state.clientFilters.length; i++) {
   179        filteredList = filteredList.filter(this.state.clientFilters[i]);
   180      }
   181      return filteredList;
   182    },
   183    // See @this._clientMidFilter.
   184    setMidFilterPattern: function (pattern) {
   185      if (typeof(pattern) != "undefined") {
   186        this.setState({midPattern: new RegExp(pattern, "i")});
   187      }
   188    },
   189    // See @this._clientDisplayFilter.
   190    setDisplayFilterPattern: function (pattern) {
   191      if (typeof(pattern) != "undefined") {
   192        this.setState({displayPattern: new RegExp(pattern, "i")});
   193      }
   194    },
   195    isClientInList: function (target_list, client) {
   196      return target_list.some(function (el) {
   197        return el.mid == client.mid;
   198      });
   199    },
   200    removeClientFromList: function (target_list, obj) {
   201      var index = target_list.findIndex(function (el) {
   202        return el.mid == obj.mid;
   203      });
   204      if (index !== -1) {
   205        target_list.splice(index, 1);
   206      }
   207      return target_list;
   208    },
   209  };