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 };