UNPKG

slack-tui

Version:
507 lines (506 loc) 17.3 kB
#!/usr/local/bin/node var notifier = require('node-notifier'); var SlackChannel = /** @class */ (function () { function SlackChannel(team, id, name) { this._isUpdatingInfo = false; this.team = team; this.id = id; this.name = name; } SlackChannel.prototype.isUpdatingInfo = function () { return this._isUpdatingInfo; }; SlackChannel.prototype.updateInfo = function (connection) { var _this = this; this._isUpdatingInfo = true; connection.reqAPI('channels.info', { channel: this.id }, function (data) { _this._isUpdatingInfo = false; if (!data.ok) return; _this.name = data.channel.name; _this.unread_count = data.channel.unread_count; _this.team.updateChannelListView(); }); }; SlackChannel.prototype.updateContent = function () { this.team.updateContent(this.id, "#" + this.name); }; SlackChannel.prototype.postMessage = function (text) { this.team.postMessage(this.id, text); }; SlackChannel.prototype.getID = function () { return this.id; }; return SlackChannel; }()); var SlackDM = /** @class */ (function () { function SlackDM(team, id, name) { this.team = team; this.id = id; this.name = name; } SlackDM.prototype.updateContent = function () { this.team.updateContent(this.id, "@" + this.name); }; SlackDM.prototype.postMessage = function (text) { this.team.postMessage(this.id, text); }; SlackDM.prototype.getID = function () { return this.id; }; return SlackDM; }()); var SlackUser = /** @class */ (function () { function SlackUser(team, id, name) { this.team = team; this.id = id; this.name = name; } return SlackUser; }()); var SlackRTMData = /** @class */ (function () { function SlackRTMData() { } SlackRTMData.getChannelId = function (data) { if (data.type === "message") { return data.channel; } return null; }; return SlackRTMData; }()); var SlackTeam = /** @class */ (function () { function SlackTeam(config, tui) { this.name = ""; this.channelList = []; this.isNotificationSuppressed = false; this.tui = tui; this.name = config[1]; this.token = config[0]; this.connection = new SlackTeam.SlackAPI({ "token": config[0], 'logging': false, 'autoReconnect': true }); this.setRTMHandler(); this.updateChannelList(); this.updateUserList(); } SlackTeam.prototype.setRTMHandler = function () { var _this = this; this.connection.on('message', function (data) { _this.tui.view.contentBox.log(JSON.stringify(data) + "\n"); var channel_id = SlackRTMData.getChannelId(data); if (_this.currentConversation && _this.currentConversation.getID() === channel_id) { // TODO: Improve performance (change to append new message only) _this.currentConversation.updateContent(); } if (!_this.isNotificationSuppressed) { notifier.notify('New message on ' + _this.name); } }); }; SlackTeam.prototype.updateChannelListView = function () { for (var _i = 0, _a = this.channelList; _i < _a.length; _i++) { var ch = _a[_i]; if (ch.isUpdatingInfo()) return; } log("done: " + this.name); var channelSelectorList = []; for (var _b = 0, _c = this.channelList; _b < _c.length; _b++) { var ch = _c[_b]; channelSelectorList.push(ch.name + "(" + ch.unread_count + ")"); } if (!this.tui.isTeamFocused(this)) return; this.tui.view.channelBox.setItems(channelSelectorList); this.tui.view.screen.render(); }; SlackTeam.prototype.updateChannelList = function () { var _this = this; this.connection.reqAPI('channels.list', { token: this.token }, function (data) { if (!data.ok) return; _this.channelList = data.channels.map(function (e) { var ch = new SlackChannel(_this, e.id, e.name); ch.updateInfo(_this.connection); return ch; }); _this.updateChannelListView(); }); }; SlackTeam.prototype.updateUserList = function () { var _this = this; this.connection.reqAPI('users.list', { token: this.token }, function (data) { if (!data.ok) return; _this.userList = data.members.map(function (e) { return new SlackUser(this, e.id, e.name); }); _this.userSelectorList = []; for (var _i = 0, _a = _this.userList; _i < _a.length; _i++) { var u = _a[_i]; _this.userSelectorList.push("@" + u.name); } _this.tui.requestUpdateUserList(_this); }); }; SlackTeam.prototype.getChannelById = function (channelId) { for (var _i = 0, _a = this.channelList; _i < _a.length; _i++) { var ch = _a[_i]; if (ch.id == channelId) return ch; } return null; }; SlackTeam.prototype.getChannelByName = function (channelName) { for (var _i = 0, _a = this.channelList; _i < _a.length; _i++) { var ch = _a[_i]; if (ch.name == channelName) return ch; } return null; }; SlackTeam.prototype.getCanonicalChannelName = function (str) { return str.replace(/\(.*\)/g, ""); }; SlackTeam.prototype.selectChannel = function (channelName) { var ch = this.getChannelByName(this.getCanonicalChannelName(channelName)); if (!ch) return; this.currentConversation = ch; ch.updateContent(); }; SlackTeam.prototype.getUserName = function (userID) { for (var _i = 0, _a = this.userList; _i < _a.length; _i++) { var u = _a[_i]; if (u.id === userID) return u.name; } return null; }; SlackTeam.prototype.sendMessage = function (text) { if (!this.currentConversation) return; this.currentConversation.postMessage(text); }; SlackTeam.prototype.postMessage = function (channelID, text) { var _this = this; var data = new Object(); data.text = text; data.channel = channelID; data.as_user = true; this.isNotificationSuppressed = true; setTimeout(function () { _this.isNotificationSuppressed = false; }, 1000); // APIのchat.postMessageを使ってメッセージを送信する this.connection.reqAPI("chat.postMessage", data); }; SlackTeam.prototype.updateContent = function (id, name_for_id) { var _this = this; var view = this.tui.view; var connection = this.connection; view.contentBox.setContent(""); view.contentBox.setLabel(this.name + "/" + name_for_id); view.contentBox.log("Loading " + name_for_id + "(" + id + ") ..."); connection.reqAPI('conversations.history', { channel: id }, function (data) { if (!data.ok) { view.contentBox.log("Failed: " + JSON.stringify(data) + "\n"); return; } view.contentBox.setContent(""); var messages = data.messages.map(function (e) { var head = (_this.getUserName(e.user) + " ").substr(0, 10); return head + ":" + e.text; }).reverse(); view.contentBox.log(messages.join("\n")); }); }; SlackTeam.prototype.openIM = function (user_id, name_for_id) { var _this = this; var view = this.tui.view; var connection = this.connection; view.contentBox.setContent(""); view.contentBox.setLabel(this.name + "/@" + name_for_id); view.contentBox.log("Opening IM with @" + name_for_id + "(" + user_id + ") ..."); connection.reqAPI('im.open', { user: user_id }, function (data) { if (!data.ok) { view.contentBox.log("Failed: " + JSON.stringify(data) + "\n"); return; } var channel_id = data.channel.id; _this.currentConversation = new SlackDM(_this, channel_id, name_for_id); _this.currentConversation.updateContent(); }); }; SlackTeam.SlackAPI = require('slackbotapi'); return SlackTeam; }()); var SlackTUIView = /** @class */ (function () { function SlackTUIView(tui) { var _this = this; this.tui = tui; var blessed = require('blessed'); // Create a screen object. this.screen = blessed.screen({ smartCSR: true, fullUnicode: true, dockBorders: true }); this.screen.title = 'slack-tui'; this.teamBox = blessed.list({ top: 0, left: 0, width: '25%', height: '25%+1', tags: true, border: { type: 'line' }, label: ' Teams ', style: { border: { fg: '#f0f0f0' }, selected: { bg: 'red' }, focus: { border: { fg: '#00ff00' } } }, keys: true }); this.screen.append(this.teamBox); this.channelBox = blessed.list({ top: '25%', left: 0, width: '25%', height: '25%+1', tags: true, border: { type: 'line' }, style: { //fg: 'white', //bg: 'magenta', border: { fg: '#f0f0f0' }, selected: { bg: 'red' }, focus: { border: { fg: '#00ff00' } } }, label: ' Channels ', keys: true }); this.screen.append(this.channelBox); this.userBox = blessed.list({ top: '50%', left: 0, width: '25%', height: '50%', tags: true, border: { type: 'line' }, style: { //fg: 'white', //bg: 'magenta', border: { fg: '#f0f0f0' }, selected: { bg: 'red' }, focus: { border: { fg: '#00ff00' } } }, label: ' Users ', keys: true }); this.screen.append(this.userBox); this.contentBox = blessed.log({ top: 0, left: '25%', width: '75%', height: '80%+1', content: "\n{green-bg}Welcome to SlackTUI!{/green-bg}\nUse {red-fg}Tab{/red-fg} key to move box focus.\nUse cursor keys to choose item.\n\t\t\t", tags: true, border: { type: 'line' }, style: { border: { fg: '#f0f0f0' }, focus: { border: { fg: '#00ff00' } } }, keys: true, scrollable: true }); this.screen.append(this.contentBox); this.inputBox = blessed.textbox({ top: '80%', left: '25%', width: '75%', height: '20%+1', content: 'Hello {bold}world{/bold}!', tags: true, border: { type: 'line' }, style: { fg: 'white', border: { fg: '#f0f0f0' }, focus: { border: { fg: '#00ff00' } } }, keys: true }); this.screen.append(this.inputBox); this.inputBox.on('submit', function (text) { _this.inputBox.clearValue(); _this.inputBox.cancel(); _this.tui.sendMessage(text); }); this.teamBox.on('select', function (el, selected) { var teamName = _this.tui.getCanonicalTeamName(el.getText()); _this.tui.focusTeamByName(teamName); }); this.channelBox.on('select', function (el, selected) { _this.tui.focusedTeam.selectChannel(el.getText()); }); this.userBox.on('select', function (el, selected) { var index = _this.userBox.getItemIndex(el); if (!_this.tui.focusedTeam) return; var u = _this.tui.focusedTeam.userList[index]; if (u) { _this.tui.focusedTeam.openIM(u.id, u.name); } }); this.screen.key(['C-c'], function (ch, key) { return process.exit(0); }); this.screen.key(['t'], function (ch, key) { _this.teamBox.focus(); }); this.teamBox.key(['tab'], function (ch, key) { _this.channelBox.focus(); }); this.channelBox.key(['tab'], function (ch, key) { _this.userBox.focus(); }); this.userBox.key(['tab'], function (ch, key) { _this.inputBox.focus(); }); this.inputBox.key(['tab'], function (ch, key) { _this.contentBox.focus(); }); this.contentBox.key(['tab'], function (ch, key) { _this.teamBox.focus(); }); this.teamBox.focus(); this.screen.render(); } return SlackTUIView; }()); var SlackTUI = /** @class */ (function () { function SlackTUI() { this.fs = require("fs"); this.configFile = process.env[process.platform == "win32" ? "USERPROFILE" : "HOME"] + "/.teamlist.json"; this.tokenList = []; this.teamDict = {}; this.focusedTeam = null; this.view = new SlackTUIView(this); try { var fval = this.fs.readFileSync(this.configFile); this.tokenList = JSON.parse(fval); } catch (e) { this.view.contentBox.log("Error: failed to read " + this.configFile); this.view.contentBox.log("Please read https://github.com/hikalium/slack-tui/blob/master/README.md carefully."); } this.refreshTeamList(); } SlackTUI.prototype.getCanonicalTeamName = function (str) { return str.replace(/\(.*\)/g, ""); }; SlackTUI.prototype.refreshTeamList = function () { var teamSelectorList = []; for (var _i = 0, _a = this.tokenList; _i < _a.length; _i++) { var t = _a[_i]; teamSelectorList.push(t[1] + "(*)"); var team = new SlackTeam(t, this); this.teamDict[t[1]] = team; } this.view.teamBox.setItems(teamSelectorList); this.view.screen.render(); }; SlackTUI.prototype.isTeamFocused = function (team) { return (this.focusedTeam === team); }; SlackTUI.prototype.requestUpdateUserList = function (team) { if (!this.isTeamFocused(team)) return; if (!team.userSelectorList) return; this.view.userBox.setItems(team.userSelectorList); this.view.screen.render(); }; SlackTUI.prototype.requestLogToContentBox = function (team, data) { if (!this.isTeamFocused(team)) return; this.view.contentBox.log(data); //this.screen.render(); }; SlackTUI.prototype.requestClearContentBox = function (team) { if (!this.isTeamFocused(team)) return; this.view.contentBox.setContent(""); }; SlackTUI.prototype.requestSetLabelOfContentBox = function (team, label) { if (!this.isTeamFocused(team)) return; this.view.contentBox.setLabel(" " + label + " "); this.view.contentBox.render(); }; SlackTUI.prototype.focusTeamByName = function (teamName) { if (!this.teamDict[teamName]) return; this.focusedTeam = this.teamDict[teamName]; this.focusedTeam.updateChannelListView(); this.requestUpdateUserList(this.focusedTeam); }; SlackTUI.prototype.sendMessage = function (text) { if (!this.focusedTeam) return; this.focusedTeam.sendMessage(text); }; return SlackTUI; }()); var slackTUI = new SlackTUI(); var log = function (str) { slackTUI.view.contentBox.log(str); };