<%namespace name="lib" file="//lib.html" import="*"/> <%namespace file="//admin/_helpers.html" import="message"/> <%! from mako import exceptions from splunk import getDefault, auth from splunk import rest from splunk import util import splunk.entity as en import splunk.appserver.mrsparkle.lib.viewstate as viewstate from splunk.appserver.mrsparkle.lib.msg_pool import MsgPoolMgr, UI_MSG_POOL from splunk.appserver.mrsparkle.lib.util import build_breadcrumbs_string, current_url_path, strip_url, make_splunkhome_path from splunk.appserver.mrsparkle.lib import cached import logging import os import splunk import urllib logger = logging.getLogger('splunk.apps.launcher') # # launcher tab state # # This logic reuses the viewstate system to store the selected launcher tab # on a per-user basis. The index of the selected tab is persisted on disk # like: # # $SPLUNK_HOME/etc/users/admin/launcher/local/viewstates.conf # [home:_current] # ServerSideInclude_0_0_0.tab_index = 1 # # On load, the _current viewstate is loaded. On tab click, the JS handler # will contact the existing viewstate handler (in view.py) to POST the # updated tab index. # PLACEHOLDER_MODULE_ID = 'ServerSideInclude_0_0_0' PLACEHOLDER_TABPARAM = 'tab_index' PLACEHOLDER_APPORDER = 'app_order' PLACEHOLDER_HIDEAPPS = 'home_hide' HIDE_APPS = ['launcher','stubby'] VALID_TABS = ['welcometab', 'hometab'] def getname(entry, imgtype): icon_name = '' static_dir = os.path.join('etc', 'apps', entry['title'], 'appserver', 'static') if imgtype == 'app': img_name_start = 'appIcon' elif imgtype == 'screenshot': img_name_start = 'screenshot' else: return '' if os.path.exists(make_splunkhome_path([static_dir, '%s.png' % (img_name_start)])): icon_name = '%s.png' % (img_name_start) else: if imgtype == 'app': icon_name = 'trans.gif' elif imgtype == 'screenshot': icon_name = 'screenshot_null.png' return icon_name def retrieve_apps(order=[]): # # splunkbase app retrieval # localApps = cached.getEntities('apps/local', count=-1, __memoized_flush_cache=False) entries = {} all = {} # pop off all apps we are not interested in for title, app in localApps.items(): is_visible = util.normalizeBoolean(app['visible']) entry = { 'disabled': util.normalizeBoolean(app['disabled']), 'canEnable': app.getLink('enable'), 'desc': app['description'] if app.get('description') else _('No description has been provided for this app. Please update app.conf for your app.'), 'label': app['label'], 'title': title, 'needsSetup': app.getLink('setup') and app['configured'] == '0', 'updateAvailable': app.getLink('update'), 'isVisible': is_visible } all[title] = entry if is_visible: entries[title] = entry applist = [] for title in order: if title in entries: applist.append(entries[title]) del entries[title] # Sort entries by case insensitive title def _cmp_app(a, b): return cmp(a['label'].lower(), b['label'].lower()) # sort remaining entries entries = entries.values() entries.sort(_cmp_app) applist += entries return applist, all def getAvailableManagerEndpoints(): endpoints = cached.getEntities('data/ui/manager', count=-1, namespace='search') return set(endpoints.keys()) launcher_settings = splunk.clilib.cli_common.getConfStanza('launcher', 'settings') %> <% namespace = APP['id'] persisted = viewstate.get(VIEW['id'], viewstate_id=None, namespace=namespace, owner=None) if persisted.modules.get(PLACEHOLDER_MODULE_ID): selectedTab = persisted.modules[PLACEHOLDER_MODULE_ID].get(PLACEHOLDER_TABPARAM, 'welcometab') appOrder = persisted.modules[PLACEHOLDER_MODULE_ID].get(PLACEHOLDER_APPORDER, 'search').split(',') else: selectedTab = 'welcometab' appOrder = ['search'] if selectedTab not in VALID_TABS: selectedTab = 'welcometab' hideApps = HIDE_APPS + launcher_settings.get('home_hide', '').split(',') breadcrumbs = build_breadcrumbs_string( [ (_('Home'), '/app/launcher/home') ]) visible_apps, all_apps = retrieve_apps(appOrder) visible_apps = [x for x in visible_apps if x['title'] not in hideApps] visible_apps_count = len(visible_apps) visible_apps_byname = dict([ (app['title'], app) for app in visible_apps]) updateCount = len([x for x in all_apps.values() if x['updateAvailable']]) invisible_setup_apps = [x for x in all_apps.values() if x['needsSetup'] and not x['isVisible'] ] welcome_app_names = [appname.strip() for appname in launcher_settings.get('welcome_apps', '').split(',')] welcome_apps = [ visible_apps_byname[appname] for appname in welcome_app_names if appname in visible_apps_byname ] welcome_apps_count = len(welcome_apps) managerEndpoints = getAvailableManagerEndpoints() msgid = cherrypy.request.params.get('msgid') msgobj = None if msgid: msgobj = MsgPoolMgr.get_poolmgr_instance()[UI_MSG_POOL].pop(msgid) # only display the welcome tab for admins with permissions to manage inputs showTabs = 'data_inputs_monitor' in managerEndpoints %> <%lib:add_script_block> var this_url = ${jsonify(strip_url(current_url_path()))}; /** * Persists the currently selected tab index to the viewstate system * See python section above for full details */ function persistTabState(newTabId) { var vsUri = Splunk.util.make_url( 'app', Splunk.util.getCurrentApp(), Splunk.util.getCurrentView(), 'home:_current' ); $.ajax({ type: 'POST', url: vsUri, data: '${PLACEHOLDER_MODULE_ID}.${PLACEHOLDER_TABPARAM}=' + encodeURIComponent(newTabId), dataType: 'json' }); } /** * Persists the application order after the user changes it via drag and drop */ function persistAppOrder() { var applist = []; $('.launcherAppsList li').each(function() { var app = $(this).attr('app'); applist.push(app); }); applist = applist.join(','); var vsUri = Splunk.util.make_url( 'app', Splunk.util.getCurrentApp(), Splunk.util.getCurrentView(), 'home:_current' ); $.ajax({ type: 'POST', url: vsUri, data: '${PLACEHOLDER_MODULE_ID}.${PLACEHOLDER_APPORDER}=' + encodeURIComponent(applist), dataType: 'json' }); } /** * Click event binder for tab clicks. This overlays the click handler * defined by the tabify.js library so that we can persist the index * of the selected tab */ function attachTabPersistence(tabId) { $(tabId).bind('click', function(evt) { var el = $(evt.target); if (!el.is('a')) return false; persistTabState(el.attr('id')); addListShadow(); }); } /** * Click event binder for app list item clicks. Makes entire li a link * to the href of the internally contained link. */ function attachAppListClickHandler() { // set up welcome link clicks functions $('ul.launcherAppsList li .launcherApplistBackground, ul.launcherLinks li .launcherApplistBackground').not('.launcherMsg').click(function(evt){ var t = evt.target; if ($(t).is('div.reorderHandle')) { return false; } var href = $(this).find('a').attr('href'); if (href) { window.location = href; } return false; }); } /** * Handle clicks of the enable app button */ function attachEnableClickHandler() { $('button.enableapp').click(function(evt) { var t = evt.target; var parent = $(t).parents('li[app]'); var app = parent.attr('app'); $('#actionform').attr('action', Splunk.util.make_url('manager', 'appinstall', app, 'enable')); $('#actionform').submit(); return false; }); } /** * Handle clicks of the setup app button */ function attachSetupClickHandler() { $('button.setupapp').click(function(evt) { var t = evt.target; var parent = $(t).parents('li[app]'); var app = parent.attr('app'); // Build URLS // this page -> setup url -> appinstall checkstatus (in case of restart required) -> back to this page var checkstatus = '/' + ['manager', 'appinstall', app, 'checkstatus'].join('/') + '?' + Splunk.util.propToQueryString({return_to: this_url}); var setupurl = Splunk.util.make_url('manager', app, 'apps', 'local', app, 'setup') + '?' + Splunk.util.propToQueryString({action: 'edit', redirect_override: checkstatus}); window.location = setupurl; return false; }); } /** * Setup drag/drop re-ordering of apps */ function setupReordering() { $(".launcherAppsList").sortable({ axis: 'y', handle: 'div.reorderHandle', update: function(event, ui) { $(".launcherAppsList .last").removeClass("last"); $(".launcherAppsList li:last").addClass("last"); if (!$($(".launcherAppsList .first")[0]).hasClass("launcherMsg")) { $(".launcherAppsList .first").removeClass("first"); $(".launcherAppsList li:first").addClass("first"); } persistAppOrder(); } }); $(".launcher-applist-wrapper").hover( function() { $($(this).find("div.reorderHandle")).show(); }, function() { $($(this).find("div.reorderHandle")).hide(); } ); } /** * Set the fake list shadow */ function addListShadow() { $(".launcherShadow").each(function() { var height = $(this).parent("ul.launcherLinks").height(); var width = $(this).parent("ul.launcherLinks").width() - 25; $(this).css("height", height); $(this).css("width", width); }); } /** * Add some class names for styling */ function addClassNames() { //add first/class class names to the items under the list in welcome tab $("#welcome ul.launcherLinks li:first").addClass("first"); var lastItem = $("#welcome ul.launcherLinks li:last"); if (lastItem.hasClass("launcherShadow")) { lastItem = lastItem.prev(); } lastItem.addClass("last"); //add first/class class names to the items under the list in welcome tab if (!$("#home ul.launcherLinks li:first").hasClass("first")) { $("#home ul.launcherLinks ul.launcherAppsList li:first").addClass("first"); } $("#home ul.launcherLinks ul.launcherAppsList li:last").addClass("last"); //add a class to uniquely identify firefox browser 3.0 to 3.5 var browserVersion = jQuery.browser.version; if ((browserVersion > "1.9.0") && (browserVersion < "1.9.1")) { $("body").addClass("firefox3"); } } $(document).ready(function(){ var logger = Splunk.Logger.getLogger("splunk.launcher"); % if showTabs: tabify('#appTabs'); % endif attachTabPersistence('#appTabs'); attachAppListClickHandler(); attachEnableClickHandler(); attachSetupClickHandler(); setupReordering(); addListShadow(); addClassNames(); var $current = $('.current'); var shownTabID = $current.children('a').attr('idx'); }); <%def name="displayApp(app, dragable, offset, count)"> <% display_label = _(app['label']) display_desc = _(app['desc']) %>
  • % if dragable: % endif
    ${display_label|h} % if len(display_desc) > 500: <% display_desc = display_desc + '...' %> % endif

    ${display_desc|h}

    % if app['canEnable']: % elif app['needsSetup']: % endif
  • % if msgobj: <%call expr="message(msgobj.text, msgobj.severity, msgobj)"> % endif
    ${csrf_hidden_input()}
    % if showTabs:
    % endif
    % if showTabs:

    ${_('Welcome to Splunk')}


    ${_("Don\'t want to see this page? Select a default app to launch after sign in.") % dict(url=make_url(['/manager/search/authentication/changepassword', cherrypy.session['user'].get('name')], _qs=dict(action='edit')))}
    % endif

    ${_('Your Apps')}

    % if 'data_inputs_monitor' in managerEndpoints:

    ${_('Do more with Splunk')}

    % endif

    ${_('Manage Splunk')}


    ${_("Don\'t want to see this page? Select a default app to launch after sign in.") % dict(url=make_url(['manager', namespace, 'authentication', 'changepassword', cherrypy.session['user'].get('name')], _qs=dict(action='edit')))}