Dev > Team

Usage Analytics

Shows which tools are used, when and by whom, and which are never used. Opt-in, and it never records document names. Shift+Click for settings and Excel export.

Tab and panelDev > Team
KindButton

Status

Untested Never executed inside Navisworks. Passed the headless checks only.

The public ask

No public source is on record for this tool.

Events it listens to

It needs these Navisworks event hooks, so installing it also copies the shared hooks folder:

  • after-command
  • before-command

Files

Paths are relative to the Playground.extension folder.

  • Dev.tab/Team.panel/Usage_Analytics.pushbutton/bundle.yaml
  • Dev.tab/Team.panel/Usage_Analytics.pushbutton/config.py
  • Dev.tab/Team.panel/Usage_Analytics.pushbutton/icon.dark.png
  • Dev.tab/Team.panel/Usage_Analytics.pushbutton/icon.png
  • Dev.tab/Team.panel/Usage_Analytics.pushbutton/icon.small.dark.png
  • Dev.tab/Team.panel/Usage_Analytics.pushbutton/icon.small.png
  • Dev.tab/Team.panel/Usage_Analytics.pushbutton/script.py

Install

  1. Only this tool. In Navisworks, click pyNavis > Playground, search for Usage Analytics, tick it and click Install.
  2. The whole extension. Download Playground.extension.zip, unzip it, put the Playground.extension folder in %APPDATA%\pyNavis\extensions\, and click pyNavis > Reload. Usage Analytics is on the Dev tab, Team panel.

You need pyNavis 1.3.0 or later.

Tried it? Tell us whether it worked or not. That report is what moves a tool up the status ladder.

Report

Source

The tool's own files, word for word as published in pynavis/Playground. Paths are relative to the Playground.extension folder.

script.py

The script that runs on a click.

Dev.tab/Team.panel/Usage_Analytics.pushbutton/script.py View on GitHub
# -*- coding: utf-8 -*-
"""Reports which pyNavis tools are used, how often and by whom (opt-in)."""
from pynavis import forms, toast

from namo import paths, ribbon, usage


def plural(count, one, many):
    return '%s %s' % ('{:,}'.format(count), one if count == 1 else many)


def run():
    settings = usage.load_settings()
    rows = usage.read_rows(usage.report_folders(settings))
    if not settings['enabled'] and not rows:
        # Nothing recorded and recording is off: explain exactly what it keeps, then ask.
        if globals().get('__runner__'):
            toast.info('Usage Analytics is off', 'Turn it on from the ribbon; it asks first.')
            return
        agreed = forms.confirm(
            'Usage Analytics records which pyNavis tools are run: the time, your user name, this '
            'computer\'s name, the tool and how long it took. It never records document names, file '
            'paths or model data.\n\nTurn it on?', title='Usage Analytics')
        if agreed:
            usage.save_settings({'enabled': True, 'asked': True})
            toast.success('Usage Analytics is on',
                          'Run a few tools, then click it again for the report. Shift+Click turns it off.')
        return                                      # No: say nothing
    if not rows:
        toast.info('No usage recorded yet', 'Run a few tools, then click Usage Analytics again.')
        return
    summary = usage.aggregate(rows, ribbon.buttons())
    shared = settings.get('shared') and paths.team_available()
    scope = 'Everyone writing to the team folder.' if shared else 'This computer.'
    if not settings['enabled']:
        scope += ' Recording is off now: Shift+Click Usage Analytics to turn it back on.'
    usage.print_report(summary, scope)
    toast.success('Usage report: %s' % plural(summary['runs'], 'run', 'runs'),
                  '%s, %s. Shift+Click for settings and Excel export.'
                  % (plural(summary['tools'], 'tool', 'tools'), plural(summary['users'], 'person', 'people')))


run()

config.py

The Shift+Click action.

Dev.tab/Team.panel/Usage_Analytics.pushbutton/config.py View on GitHub
# -*- coding: utf-8 -*-
"""Turns Usage Analytics on or off, picks where it writes, and exports the data to Excel."""
import os

from pynavis import forms, toast

from namo import paths, ribbon, ui, usage, xlsx


def state_toast(saved):
    """One toast for what was saved, honest about a team folder that is not there."""
    title = 'Usage Analytics is %s' % ('on' if saved['enabled'] else 'off')
    if saved['shared'] and not paths.team_available():
        toast.warning(title, 'No team folder is reachable, so records stay on this computer. '
                             'Set the shared folder in Playground Settings.')
    else:
        toast.success(title, 'Records go to %s.' % ('the team folder' if saved['shared'] else 'this computer'))


def export(saved):
    """True when a workbook was written or the failure was reported; False on cancel."""
    rows = usage.read_rows(usage.report_folders(saved))
    if not rows:
        toast.info('Nothing to export yet', 'No usage has been recorded. Turn recording on and run a few tools.')
        return True
    path = forms.save_file(filter='Excel workbooks (*.xlsx)|*.xlsx', default_name='Playground usage.xlsx',
                           title='Export usage')
    if path is None:
        return False
    try:
        xlsx.write_simple(path, usage.xlsx_sheets(usage.aggregate(rows, ribbon.buttons())),
                          title='Playground usage')
    except (IOError, OSError) as error:
        toast.error('Could not write the workbook', 'Close it in Excel, then try again. %s' % error)
    else:
        toast.success('Exported %s run%s' % ('{:,}'.format(len(rows)), '' if len(rows) == 1 else 's'),
                      os.path.basename(path))
    return True


def run():
    settings = usage.load_settings()
    values = ui.form('Usage Analytics', [
        {'kind': 'check', 'key': 'enabled', 'label': 'Record which tools I run', 'default': settings['enabled']},
        {'kind': 'radio', 'key': 'shared', 'label': 'Write the records to',
         'options': [('This computer', False), ('The team folder (one file per person)', True)],
         'default': settings['shared'], 'fallback': None},
        {'kind': 'label', 'text': 'Only the time, user, computer, tool and duration are recorded, never document names.',
         'muted': True},
        {'kind': 'check', 'key': 'export', 'label': 'Export the records to Excel now', 'default': False},
    ], ok='Save')
    if values is None:
        return                                      # cancelled: say nothing
    saved = usage.save_settings({'enabled': values['enabled'], 'shared': values['shared'], 'asked': True})
    # The settings are saved either way; the export, when asked for, reports instead.
    if not (values['export'] and export(saved)):
        state_toast(saved)


if globals().get('__runner__'):
    toast.info('The Usage Analytics settings need the Navisworks window', 'They cannot open under pynavis run.')
else:
    run()

Library modules this tool uses

From the shared namo library, which installs with every tool. Each name opens the module on GitHub.

  • namo.pathsWhere Playground keeps its files, and how it writes them safely.
  • namo.ribbonThe ribbon as data: every pyNavis button and every native Navisworks command, and safe ways to run them from code. Shared by the Command Palette, macros, the Hotkey Manager, usage analytics and the Environment Doctor.
  • namo.uiWPF building blocks for Playground tools, themed from the pyNavis design system.
  • namo.usageUsage Analytics: which tools people run, when, and for how long. Opt-in.
  • namo.xlsxStyled Excel (.xlsx) writer: fills, number formats, widths, frozen headers, autofilter, merged title rows, hyperlinks and embedded images. No Excel needed.

bundle.yaml

The bundle contract: the keys pyNavis reads for this tool.

Dev.tab/Team.panel/Usage_Analytics.pushbutton/bundle.yaml View on GitHub
title: Usage\nAnalytics
tooltip: Shows which tools are used, when and by whom, and which are never used. Opt-in, and it never records document names. Shift+Click for settings and Excel export.