mirror of
https://github.com/munki/munki.git
synced 2026-04-20 19:50:36 -05:00
Track user choices for install/removal; employ a different strategy for determining if an updatecheck is needed; display links to updates page for some item statuses
This commit is contained in:
@@ -33,6 +33,7 @@ from MSUStatusController import MSUStatusController
|
||||
import munki
|
||||
import msuhtml
|
||||
import msulog
|
||||
import MunkiItems
|
||||
|
||||
class MSUAppDelegate(NSObject):
|
||||
|
||||
@@ -68,23 +69,26 @@ class MSUAppDelegate(NSObject):
|
||||
lastcheck = NSDate.date()
|
||||
else:
|
||||
lastcheck = munki.pref('LastCheckDate')
|
||||
max_cache_age = munki.pref('CheckResultsCacheSeconds')
|
||||
# if there is no lastcheck timestamp, check for updates.
|
||||
if not lastcheck:
|
||||
self.mainWindowController.checkForUpdates()
|
||||
|
||||
# otherwise, only check for updates if the last check is over the
|
||||
# configured manualcheck cache age max.
|
||||
max_cache_age = munki.pref('CheckResultsCacheSeconds')
|
||||
if lastcheck.timeIntervalSinceNow() * -1 > int(max_cache_age):
|
||||
elif lastcheck.timeIntervalSinceNow() * -1 > int(max_cache_age):
|
||||
# check for updates if the last check is over the
|
||||
# configured manualcheck cache age max.
|
||||
self.mainWindowController.checkForUpdates()
|
||||
|
||||
# load the initial only if we are not already loading something else.
|
||||
elif MunkiItems.updateCheckNeeded():
|
||||
# check for updates if we have optional items selected for install
|
||||
# or removal that have not yet been processed
|
||||
self.mainWindowController.checkForUpdates()
|
||||
|
||||
# load the initial view only if we are not already loading something else.
|
||||
# enables launching the app to a specific panel, eg. from URL handler
|
||||
if not self.mainWindowController.webView.isLoading():
|
||||
self.mainWindowController.loadInitialView()
|
||||
self.mainWindowController.loadInitialView()
|
||||
|
||||
# below is the URL handler for calls outside the app eg. web clicks
|
||||
def applicationWillFinishLaunching_(self, notification):
|
||||
'''Installs URL handler for calls outside the app eg. web clicks'''
|
||||
man = NSAppleEventManager.sharedAppleEventManager()
|
||||
man.setEventHandler_andSelector_forEventClass_andEventID_(
|
||||
self,
|
||||
@@ -93,6 +97,7 @@ class MSUAppDelegate(NSObject):
|
||||
struct.unpack(">i", "GURL")[0])
|
||||
|
||||
def openURL_withReplyEvent_(self, event, replyEvent):
|
||||
'''Handle openURL messages'''
|
||||
keyDirectObject = struct.unpack(">i", "----")[0]
|
||||
url = event.paramDescriptorForKeyword_(keyDirectObject).stringValue().decode('utf8')
|
||||
NSLog("Called by external URL: %@", url)
|
||||
|
||||
@@ -232,9 +232,9 @@ class MSUMainWindowController(NSWindowController):
|
||||
|
||||
# all done checking and/or installing: display results
|
||||
self.resetAndReload()
|
||||
if self._update_queue:
|
||||
# more stuff pending? Let's do it
|
||||
self._update_queue.clear()
|
||||
|
||||
if MunkiItems.updateCheckNeeded():
|
||||
# more stuff pending? Let's do it...
|
||||
self.updateNow()
|
||||
|
||||
@AppHelper.endSheetMethod
|
||||
@@ -355,15 +355,19 @@ class MSUMainWindowController(NSWindowController):
|
||||
def checkForUpdates(self, suppress_apple_update_check=False):
|
||||
'''start an update check session'''
|
||||
# attempt to start the update check
|
||||
if self._update_in_progress:
|
||||
return
|
||||
result = munki.startUpdateCheck(suppress_apple_update_check)
|
||||
if result == 0:
|
||||
self._update_in_progress = True
|
||||
self.displayUpdateCount()
|
||||
self.managedsoftwareupdate_task = "manualcheck"
|
||||
NSApp.delegate().statusController.startMunkiStatusSession()
|
||||
self.markRequestedItemsAsProcessing()
|
||||
else:
|
||||
self.munkiStatusSessionEnded_(2)
|
||||
|
||||
def kickOffUpdateSession(self):
|
||||
def kickOffInstallSession(self):
|
||||
'''start an update install/removal session'''
|
||||
# check for need to logout, restart, firmware warnings
|
||||
# warn about blocking applications, etc...
|
||||
@@ -407,6 +411,14 @@ class MSUMainWindowController(NSWindowController):
|
||||
for item in install_info.get('managed_installs', [])]
|
||||
items_to_be_removed_names = [item['name']
|
||||
for item in install_info.get('removals', [])]
|
||||
|
||||
for name in items_to_be_installed_names:
|
||||
# remove names for user selections since we are installing
|
||||
MunkiItems.user_install_selections.discard(name)
|
||||
|
||||
for name in items_to_be_removed_names:
|
||||
# remove names for user selections since we are removing
|
||||
MunkiItems.user_removal_selections.discard(name)
|
||||
|
||||
for item in MunkiItems.getOptionalInstallItems():
|
||||
new_status = None
|
||||
@@ -426,7 +438,7 @@ class MSUMainWindowController(NSWindowController):
|
||||
NSLog('markRequestedItemsAsProcessing')
|
||||
for item in MunkiItems.getOptionalInstallItems():
|
||||
new_status = None
|
||||
NSLog('Status for %s is %s' % (item['name'], item['status']))
|
||||
#NSLog('Status for %s is %s' % (item['name'], item['status']))
|
||||
if item['status'] == 'install-requested':
|
||||
NSLog('Setting status for %s to "downloading"' % item['name'])
|
||||
new_status = u'downloading'
|
||||
@@ -440,17 +452,16 @@ class MSUMainWindowController(NSWindowController):
|
||||
def updateNow(self):
|
||||
'''If user has added to/removed from the list of things to be updated,
|
||||
run a check session. If there are no more changes, proceed to an update
|
||||
installation session'''
|
||||
installation session if items to be installed/removed are exclusively
|
||||
those selected by the user in this session'''
|
||||
if self.stop_requested:
|
||||
# reset the flag
|
||||
self.stop_requested = False
|
||||
self.resetAndReload()
|
||||
return
|
||||
current_self_service = MunkiItems.SelfService()
|
||||
if current_self_service != self.cached_self_service:
|
||||
NSLog('selfService choices changed')
|
||||
# recache SelfService
|
||||
self.cached_self_service = current_self_service
|
||||
if MunkiItems.updateCheckNeeded():
|
||||
# any item status changes that require an update check?
|
||||
NSLog('updateCheck needed')
|
||||
msulog.log("user", "check_then_install_without_logout")
|
||||
# since we are just checking for changed self-service items
|
||||
# we can suppress the Apple update check
|
||||
@@ -458,7 +469,6 @@ class MSUMainWindowController(NSWindowController):
|
||||
self._update_in_progress = True
|
||||
self.displayUpdateCount()
|
||||
result = munki.startUpdateCheck(suppress_apple_update_check)
|
||||
result = 0
|
||||
if result:
|
||||
NSLog("Error starting check-then-install session: %s" % result)
|
||||
self.munkiStatusSessionEnded_(2)
|
||||
@@ -466,17 +476,19 @@ class MSUMainWindowController(NSWindowController):
|
||||
self.managedsoftwareupdate_task = "checktheninstall"
|
||||
NSApp.delegate().statusController.startMunkiStatusSession()
|
||||
self.markRequestedItemsAsProcessing()
|
||||
elif not self._alertedUserToOutstandingUpdates and MunkiItems.updatesContainNonOptionalItems():
|
||||
elif (not self._alertedUserToOutstandingUpdates
|
||||
and MunkiItems.updatesContainNonUserSelectedItems()):
|
||||
# current list of updates contains some not explicitly chosen by the user
|
||||
NSLog('updateCheck not needed, items require user approval')
|
||||
self._update_in_progress = False
|
||||
self.displayUpdateCount()
|
||||
self.loadUpdatesPage_(self)
|
||||
self._alertedUserToOutstandingUpdates = True
|
||||
self.alert_controller.alertToExtraUpdates()
|
||||
else:
|
||||
NSLog('selfService choices unchanged')
|
||||
NSLog('updateCheck not needed')
|
||||
self._alertedUserToOutstandingUpdates = False
|
||||
self.kickOffUpdateSession()
|
||||
self.kickOffInstallSession()
|
||||
|
||||
def getUpdateCount(self):
|
||||
'''Get the count of effective updates'''
|
||||
@@ -672,10 +684,8 @@ class MSUMainWindowController(NSWindowController):
|
||||
|
||||
elif self.getUpdateCount() == 0:
|
||||
# no updates, this button must say "Check Again"
|
||||
self._update_in_progress = True
|
||||
self.loadUpdatesPage_(self)
|
||||
self.displayUpdateCount()
|
||||
self.checkForUpdates()
|
||||
self.loadUpdatesPage_(self)
|
||||
else:
|
||||
# must say "Update"
|
||||
self.updateNow()
|
||||
@@ -789,14 +799,9 @@ class MSUMainWindowController(NSWindowController):
|
||||
# update count badges
|
||||
self.displayUpdateCount()
|
||||
|
||||
if (previous_status in ['update-will-be-installed', 'will-be-installed', 'will-be-removed']
|
||||
or item['status'] in ['install-requested', 'removal-requested']):
|
||||
# item was processed and cached for install or removal. Need to run
|
||||
# an updatecheck session to possibly remove other items (dependencies
|
||||
# or updates) from the pending list
|
||||
if MunkiItems.updateCheckNeeded():
|
||||
# check for updates after a short delay so UI changes visually complete first
|
||||
self.performSelector_withObject_afterDelay_(self.checkForUpdates, True, 1.0)
|
||||
self._update_in_progress = True
|
||||
|
||||
def myItemsActionButtonClicked_(self, item_name):
|
||||
'''this method is called from JavaScript when the user clicks
|
||||
@@ -810,18 +815,11 @@ class MSUMainWindowController(NSWindowController):
|
||||
return
|
||||
item.update_status()
|
||||
|
||||
if item.get('will_be_installed') or item.get('will_be_removed'):
|
||||
# item was processed and cached for install or removal. Need to run
|
||||
# an updatecheck session to possibly remove other items (dependencies
|
||||
# or updates) from the pending list
|
||||
if MunkiItems.updateCheckNeeded():
|
||||
if not self._update_in_progress:
|
||||
self._update_in_progress = True
|
||||
self.displayUpdateCount()
|
||||
self.checkForUpdates(suppress_apple_update_check=True)
|
||||
self.performSelector_withObject_afterDelay_(self.checkForUpdates, True, 0.1)
|
||||
else:
|
||||
# add to queue to check later
|
||||
# TO-DO: fix this as this can trigger an install as well
|
||||
#self._update_queue.add(item['name'])
|
||||
# will happen later...
|
||||
pass
|
||||
|
||||
self.displayUpdateCount()
|
||||
@@ -835,10 +833,6 @@ class MSUMainWindowController(NSWindowController):
|
||||
btn.setInnerText_(item['myitem_action_text'])
|
||||
status_line.setInnerText_(item['status_text'])
|
||||
status_line.setClassName_('status %s' % item['status'])
|
||||
if not self._update_in_progress:
|
||||
if item['status'] in ['will-be-installed', 'update-will-be-installed',
|
||||
'will-be-removed']:
|
||||
self.updateNow()
|
||||
|
||||
def updateDOMforOptionalItem(self, item):
|
||||
'''Update displayed status of an item'''
|
||||
|
||||
@@ -33,6 +33,8 @@ from AppKit import *
|
||||
|
||||
import FoundationPlist
|
||||
|
||||
user_install_selections = set()
|
||||
user_removal_selections = set()
|
||||
|
||||
# place to cache our expensive-to-calculate data
|
||||
_cache = {}
|
||||
@@ -63,6 +65,12 @@ def getOptionalInstallItems():
|
||||
return _cache['optional_install_items']
|
||||
|
||||
|
||||
def updateCheckNeeded():
|
||||
'''Returns True if any item in optional installs list has 'updatecheck_needed' == True'''
|
||||
return len([item for item in getOptionalInstallItems()
|
||||
if item.get('updatecheck_needed')]) != 0
|
||||
|
||||
|
||||
def optionalItemForName_(item_name):
|
||||
for item in getOptionalInstallItems():
|
||||
if item['name'] == item_name:
|
||||
@@ -72,12 +80,13 @@ def optionalItemForName_(item_name):
|
||||
|
||||
def getOptionalWillBeInstalledItems():
|
||||
return [item for item in getOptionalInstallItems()
|
||||
if item['status'] in ['will-be-installed', 'update-will-be-installed']]
|
||||
if item['status'] in ['install-requested', 'will-be-installed',
|
||||
'update-will-be-installed', 'install-error']]
|
||||
|
||||
|
||||
def getOptionalWillBeRemovedItems():
|
||||
return [item for item in getOptionalInstallItems()
|
||||
if item['status'] == 'will-be-removed']
|
||||
if item['status'] in ['removal-requested', 'will-be-removed', 'removal-error']]
|
||||
|
||||
|
||||
def getUpdateList():
|
||||
@@ -134,7 +143,7 @@ def updatesRequireRestart():
|
||||
if 'Restart' in item.get('RestartAction', '')]) > 0
|
||||
|
||||
|
||||
def updatesContainNonOptionalItems():
|
||||
def updatesContainNonUserSelectedItems():
|
||||
'''Does the list of updates contain items not selected by the user?'''
|
||||
if not munki.munkiUpdatesContainAppleItems() and getAppleUpdates():
|
||||
# available Apple updates are not user selected
|
||||
@@ -143,11 +152,11 @@ def updatesContainNonOptionalItems():
|
||||
install_items = install_info.get('managed_installs', [])
|
||||
removal_items = install_info.get('removals', [])
|
||||
filtered_installs = [item for item in install_items
|
||||
if item['name'] not in SelfService().installs()]
|
||||
if item['name'] not in user_install_selections]
|
||||
if filtered_installs:
|
||||
return True
|
||||
filtered_uninstalls = [item for item in removal_items
|
||||
if item['name'] not in SelfService().uninstalls()]
|
||||
if item['name'] not in user_removal_selections]
|
||||
if filtered_uninstalls:
|
||||
return True
|
||||
return False
|
||||
@@ -303,7 +312,8 @@ class MSUHTMLFilter(HTMLParser):
|
||||
|
||||
|
||||
def filtered_html(text):
|
||||
'''Returns filtered HTML for use in description paragraphs'''
|
||||
'''Returns filtered HTML for use in description paragraphs
|
||||
or converts plain text into basic HTML for the same use'''
|
||||
parser = MSUHTMLFilter()
|
||||
parser.feed(text)
|
||||
if parser.tag_count:
|
||||
@@ -363,15 +373,25 @@ class SelfService(object):
|
||||
|
||||
|
||||
def subscribe(item):
|
||||
'''Add item to SelfServeManifest's managed_installs.
|
||||
Also track user selections.'''
|
||||
SelfService().subscribe(item)
|
||||
user_install_selections.add(item['name'])
|
||||
|
||||
|
||||
def unsubscribe(item):
|
||||
'''Add item to SelfServeManifest's managed_uninstalls.
|
||||
Also track user selections.'''
|
||||
SelfService().unsubscribe(item)
|
||||
user_removal_selections.add(item['name'])
|
||||
|
||||
|
||||
def unmanage(item):
|
||||
'''Remove item from SelfServeManifest.
|
||||
Also track user selections.'''
|
||||
SelfService().unmanage(item)
|
||||
user_install_selections.discard(item['name'])
|
||||
user_removal_selections.discard(item['name'])
|
||||
|
||||
|
||||
class GenericItem(dict):
|
||||
@@ -443,15 +463,15 @@ class GenericItem(dict):
|
||||
|
||||
def dependency_description(self):
|
||||
'''Return an html description of items this item depends on'''
|
||||
_description = u''
|
||||
description = u''
|
||||
prologue = NSLocalizedString(
|
||||
u'This item is required by:', u'DependencyListPrologueText')
|
||||
if self.get('dependent_items'):
|
||||
_description = u'<br/><br/><strong>' + prologue
|
||||
description = u'<strong>' + prologue
|
||||
for item in self['dependent_items']:
|
||||
_description += u'<br/> • ' + display_name(item)
|
||||
_description += u'</strong>'
|
||||
return _description
|
||||
description += u'<br/> • ' + display_name(item)
|
||||
description += u'</strong><br/><br/>'
|
||||
return description
|
||||
|
||||
def guess_developer(self):
|
||||
'''Figure out something to use for the developer name'''
|
||||
@@ -749,6 +769,10 @@ class GenericItem(dict):
|
||||
removal_text = NSLocalizedString(
|
||||
u'Will be removed', u'WillBeRemovedDisplayText')
|
||||
return '<span class="warning">%s</span>' % removal_text
|
||||
if self['status'] == 'removal-requested':
|
||||
removal_text = NSLocalizedString(
|
||||
u'Removal requested', u'RemovalRequestedDisplayText')
|
||||
return '<span class="warning">%s</span>' % removal_text
|
||||
else:
|
||||
return NSLocalizedString(u'Version', u'VersionLabel')
|
||||
|
||||
@@ -798,10 +822,13 @@ class OptionalItem(GenericItem):
|
||||
self['hide_cancel_button'] = u''
|
||||
|
||||
def _get_status(self):
|
||||
'''Calculates initial status for an item'''
|
||||
'''Calculates initial status for an item and also sets a boolean
|
||||
if a updatecheck is needed'''
|
||||
managed_update_names = getInstallInfo().get('managed_updates', [])
|
||||
self_service_installs = SelfService().installs()
|
||||
self_service_uninstalls = SelfService().uninstalls()
|
||||
self['updatecheck_needed'] = False
|
||||
self['user_directed_action'] = False
|
||||
if self.get('installed'):
|
||||
if self.get('removal_error'):
|
||||
status = u'removal-error'
|
||||
@@ -811,6 +838,7 @@ class OptionalItem(GenericItem):
|
||||
status = u'installed-not-removable'
|
||||
elif self['name'] in self_service_uninstalls:
|
||||
status = u'removal-requested'
|
||||
self['updatecheck_needed'] = True
|
||||
else: # not in managed_uninstalls
|
||||
if not self.get('needs_update'):
|
||||
if self.get('uninstallable'):
|
||||
@@ -850,6 +878,7 @@ class OptionalItem(GenericItem):
|
||||
status = u'will-be-installed'
|
||||
elif self['name'] in self_service_installs:
|
||||
status = u'install-requested'
|
||||
self['updatecheck_needed'] = True
|
||||
else: # not in managed_installs
|
||||
status = u'not-installed'
|
||||
return status
|
||||
@@ -857,28 +886,31 @@ class OptionalItem(GenericItem):
|
||||
def description(self):
|
||||
'''return a full description for the item, inserting dynamic data
|
||||
if needed'''
|
||||
_description = self['raw_description']
|
||||
start_text = ''
|
||||
if self.get('install_error'):
|
||||
_description = NSLocalizedString(
|
||||
u'<span class="warning">An installation attempt failed. '
|
||||
'Installation will be attempted again.<br/>'
|
||||
'If this situation continues, contact your systems administrator.'
|
||||
'</span><br/><br/>',
|
||||
u'InstallErrorMessage') + _description
|
||||
elif self.get('removal_error'):
|
||||
_description = NSLocalizedString(
|
||||
u'<span class="warning">A removal attempt failed. '
|
||||
'Removal will be attempted again.<br/>'
|
||||
'If this situation continues, contact your systems administrator.'
|
||||
'</span><br/><br/>',
|
||||
u'RemovalErrorMessage') + _description
|
||||
warning_text = NSLocalizedString(
|
||||
u'An installation attempt failed. '
|
||||
'Installation will be attempted again.\n'
|
||||
'If this situation continues, contact your systems administrator.',
|
||||
u'InstallErrorMessage')
|
||||
start_text += '<span class="warning">%s</span><br/><br/>' % filtered_html(warning_text)
|
||||
if self.get('removal_error'):
|
||||
warning_text = NSLocalizedString(
|
||||
u'A removal attempt failed. '
|
||||
'Removal will be attempted again.\n'
|
||||
'If this situation continues, contact your systems administrator.',
|
||||
u'RemovalErrorMessage')
|
||||
start_text += '<span class="warning">%s</span><br/><br/>' % filtered_html(warning_text)
|
||||
if self.get('dependent_items'):
|
||||
# append dependency info to description:
|
||||
_description += self.dependency_description()
|
||||
return _description
|
||||
start_text += self.dependency_description()
|
||||
|
||||
return start_text + self['raw_description']
|
||||
|
||||
def update_status(self):
|
||||
# user clicked an item action button - update the item's state
|
||||
# also sets a boolean indicating if we should run an updatecheck
|
||||
self['updatecheck_needed'] = True
|
||||
original_status = self['status']
|
||||
managed_update_names = getInstallInfo().get('managed_updates', [])
|
||||
if self['status'] == 'update-available':
|
||||
# mark the update for install
|
||||
@@ -900,6 +932,8 @@ class OptionalItem(GenericItem):
|
||||
# item is simply installed
|
||||
self['status'] = u'installed'
|
||||
unmanage(self)
|
||||
if original_status == 'removal-requested':
|
||||
self['updatecheck_needed'] = False
|
||||
elif self['status'] in ['will-be-installed', 'install-requested',
|
||||
'downloading', 'install-error']:
|
||||
# cancel install
|
||||
@@ -908,6 +942,8 @@ class OptionalItem(GenericItem):
|
||||
else:
|
||||
self['status'] = u'not-installed'
|
||||
unmanage(self)
|
||||
if original_status == 'install-requested':
|
||||
self['updatecheck_needed'] = False
|
||||
elif self['status'] == 'not-installed':
|
||||
# mark for install
|
||||
self['status'] = u'install-requested'
|
||||
@@ -940,7 +976,8 @@ class UpdateItem(GenericItem):
|
||||
self['dependent_items'] = dependentItems(self['name'])
|
||||
|
||||
def description(self):
|
||||
_description = self['raw_description']
|
||||
warning = ''
|
||||
dependent_items = ''
|
||||
if not self['status'] == 'will-be-removed':
|
||||
force_install_after_date = self.get('force_install_after_date')
|
||||
if force_install_after_date:
|
||||
@@ -951,12 +988,11 @@ class UpdateItem(GenericItem):
|
||||
forced_date_text = NSLocalizedString(
|
||||
u'This item must be installed by %s',
|
||||
u'ForcedDateWarning')
|
||||
# prepend deadline info to description.
|
||||
_description = ('<span class="warning">' + forced_date_text % date_str
|
||||
+ '</span><br><br>' + _description)
|
||||
warning = ('<span class="warning">'
|
||||
+ forced_date_text % date_str
|
||||
+ '</span><br><br>')
|
||||
if self.get('dependent_items'):
|
||||
# append dependency info to description:
|
||||
_description += self.dependency_description()
|
||||
dependent_items = self.dependency_description()
|
||||
|
||||
return _description
|
||||
return warning + dependent_items + self['raw_description']
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
@@ -1282,6 +1282,39 @@ div.title div.select {
|
||||
color: #CC0000 !important;
|
||||
}
|
||||
|
||||
div.lockup li a.follow,
|
||||
span a.follow {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
div.lockup li.install-requested a.follow,
|
||||
div.lockup li.will-be-installed a.follow,
|
||||
div.lockup li.update-will-be-installed a.follow,
|
||||
div.lockup li.removal-requested a.follow,
|
||||
div.lockup li.will-be-removed a.follow,
|
||||
span.install-requested a.follow,
|
||||
span.will-be-installed a.follow,
|
||||
span.update-will-be-installed a.follow,
|
||||
span.removal-requested a.follow,
|
||||
span.will-be-removed a.follow {
|
||||
visibility: visible;
|
||||
opacity: 0.8;
|
||||
display: inline-block;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background: url('FollowLink.png') 0 0 no-repeat;
|
||||
-webkit-background-size: 12px 12px;
|
||||
position: relative;
|
||||
left: 2px;
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
div.lockup li a.follow:hover,
|
||||
span a.follow:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
|
||||
div.lockup li.will-be-installed,
|
||||
div.lockup li.will-be-removed,
|
||||
div.lockup li.install-requested,
|
||||
@@ -1327,6 +1360,8 @@ div.lockup li.removing:after {
|
||||
-webkit-animation-duration: 1s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
div.lockup li.downloading:after, div.lockup li.preparing-removal:after,
|
||||
div.lockup li.installing:after, div.lockup li.removing:after {
|
||||
position: absolute;
|
||||
|
||||
@@ -377,6 +377,7 @@ def justUpdate():
|
||||
except (OSError, IOError):
|
||||
return 1
|
||||
|
||||
|
||||
def pythonScriptRunning(scriptname):
|
||||
"""Returns Process ID for a running python script"""
|
||||
cmd = ['/bin/ps', '-eo', 'pid=,command=']
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
<span class="label">${statusLabel} </span>
|
||||
<span class="${status}" id="${name}_status_text">
|
||||
${status_text}
|
||||
<a class="follow" href="updates.html"></a>
|
||||
</span>
|
||||
</li>
|
||||
<li class="warning">${restart_action_text}</li>
|
||||
|
||||
+4
-1
@@ -7,7 +7,10 @@
|
||||
<ul class="list">
|
||||
<li class="name" title="${display_name}"><a href="${detail_link}">${display_name}</a></li>
|
||||
<li class="genre">${category_and_developer}</li>
|
||||
<li class="${status}" id="${name}_status_text">${status_text}</li>
|
||||
<li class="${status}" id="${name}_status_text">
|
||||
${status_text}
|
||||
<a class="follow" href="updates.html"></a>
|
||||
</li>
|
||||
<li>
|
||||
<div class="msu-button small">
|
||||
<button class="button-area uppercase"
|
||||
|
||||
+6
-1
@@ -12,7 +12,12 @@
|
||||
</td>
|
||||
<td>${version_to_install}</td>
|
||||
<td>${size}</td>
|
||||
<td class="status"><span class="${status}" id="${name}_status_text">${status_text}</span></td>
|
||||
<td class="status">
|
||||
<span class="${status}" id="${name}_status_text">
|
||||
${status_text}
|
||||
<a class="follow" href="updates.html">
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="msu-button install-updates">
|
||||
<button class="button-area uppercase"
|
||||
|
||||
Reference in New Issue
Block a user