From b9944e95453530c20478b7326cf0db7637b754bd Mon Sep 17 00:00:00 2001 From: Greg Neagle Date: Thu, 3 Mar 2016 14:06:33 -0800 Subject: [PATCH 01/29] Update gurl.py to use NSURLSession on those versions of OS X that support it. Addresses issue #551. --- code/client/munkilib/gurl.py | 391 +++++++++++++++++++++++++---------- 1 file changed, 277 insertions(+), 114 deletions(-) diff --git a/code/client/munkilib/gurl.py b/code/client/munkilib/gurl.py index a1918ad2..71bfb79f 100644 --- a/code/client/munkilib/gurl.py +++ b/code/client/munkilib/gurl.py @@ -1,7 +1,7 @@ #!/usr/bin/python # encoding: utf-8 # -# Copyright 2009-2014 Greg Neagle. +# Copyright 2009-2016 Greg Neagle. # # Licensed under the Apache License, Version 2.0 (the 'License'); # you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ gurl.py Created by Greg Neagle on 2013-11-21. +Modified in Feb 2016 to add support for NSURLSession. curl replacement using NSURLConnection and friends """ @@ -32,22 +33,63 @@ from objc import super # PyLint cannot properly find names inside Cocoa libraries, so issues bogus # No name 'Foo' in module 'Bar' warnings. Disable them. # pylint: disable=E0611 -from Foundation import NSBundle -from Foundation import NSRunLoop, NSDate -from Foundation import NSObject, NSURL, NSURLConnection -from Foundation import NSMutableURLRequest -from Foundation import NSURLRequestReloadIgnoringLocalCacheData -from Foundation import NSURLResponseUnknownLength -from Foundation import NSLog -from Foundation import NSURLCredential, NSURLCredentialPersistenceNone -from Foundation import NSPropertyListSerialization -from Foundation import NSPropertyListMutableContainersAndLeaves -from Foundation import NSPropertyListXMLFormat_v1_0 -# pylint: enable=E0611 +from Foundation import NSBundle, \ + NSRunLoop, NSDate, \ + NSObject, NSURL, NSURLConnection, \ + NSMutableURLRequest, \ + NSURLRequestReloadIgnoringLocalCacheData, \ + NSURLResponseUnknownLength, \ + NSLog, \ + NSURLCredential, NSURLCredentialPersistenceNone, \ + NSPropertyListSerialization, \ + NSPropertyListMutableContainersAndLeaves, \ + NSPropertyListXMLFormat_v1_0 + +try: + from Foundation import NSURLSession, NSURLSessionConfiguration + NSURLSESSION_AVAILABLE = True +except ImportError: + NSURLSESSION_AVAILABLE = False # Disable PyLint complaining about 'invalid' names # pylint: disable=C0103 +if NSURLSESSION_AVAILABLE: + # NSURLSessionAuthChallengeDisposition enum constants + NSURLSessionAuthChallengeUseCredential = 0 + NSURLSessionAuthChallengePerformDefaultHandling = 1 + NSURLSessionAuthChallengeCancelAuthenticationChallenge = 2 + NSURLSessionAuthChallengeRejectProtectionSpace = 3 + + # NSURLSessionResponseDisposition enum constants + NSURLSessionResponseCancel = 0 + NSURLSessionResponseAllow = 1 + NSURLSessionResponseBecomeDownload = 2 + + # TLS/SSLProtocol enum constants + kSSLProtocolUnknown = 0 + kSSLProtocol3 = 2 + kTLSProtocol1 = 4 + kTLSProtocol11 = 7 + kTLSProtocol12 = 8 + kDTLSProtocol1 = 9 + + # define a helper function for block callbacks + import ctypes + import objc + _objc_so = ctypes.cdll.LoadLibrary( + os.path.join(objc.__path__[0], '_objc.so')) + PyObjCMethodSignature_WithMetaData = ( + _objc_so.PyObjCMethodSignature_WithMetaData) + PyObjCMethodSignature_WithMetaData.restype = ctypes.py_object + + def objc_method_signature(signature_str): + '''Return a PyObjCMethodSignature given a call signature in string + format''' + return PyObjCMethodSignature_WithMetaData( + ctypes.create_string_buffer(signature_str), None, False) + +# pylint: enable=E0611 # disturbing hack warning! # this works around an issue with App Transport Security on 10.11 @@ -56,6 +98,11 @@ info = bundle.localizedInfoDictionary() or bundle.infoDictionary() info['NSAppTransportSecurity'] = {'NSAllowsArbitraryLoads': True} +def NSLogWrapper(message): + '''A wrapper function for NSLog to prevent format string errors''' + NSLog('%@', message) + + ssl_error_codes = { -9800: u'SSL protocol error', -9801: u'Cipher Suite negotiation failure', @@ -111,7 +158,7 @@ ssl_error_codes = { class Gurl(NSObject): '''A class for getting content from a URL - using NSURLConnection and friends''' + using NSURLConnection/NSURLSession and friends''' # since we inherit from NSObject, PyLint issues a few bogus warnings # pylint: disable=W0232,E1002 @@ -139,8 +186,11 @@ class Gurl(NSObject): 'download_only_if_changed', False) self.cache_data = options.get('cache_data') self.connection_timeout = options.get('connection_timeout', 60) + if NSURLSESSION_AVAILABLE: + self.minimum_tls_protocol = options.get( + 'minimum_tls_protocol', kTLSProtocol1) - self.log = options.get('logging_function', NSLog) + self.log = options.get('logging_function', NSLogWrapper) self.resume = False self.response = None @@ -155,6 +205,8 @@ class Gurl(NSObject): self.expectedLength = -1 self.percentComplete = 0 self.connection = None + self.session = None + self.task = None return self def start(self): @@ -189,18 +241,34 @@ class Gurl(NSObject): if 'etag' in stored_data: request.setValue_forHTTPHeaderField_( stored_data['etag'], 'if-none-match') - self.connection = NSURLConnection.alloc().initWithRequest_delegate_( - request, self) + if NSURLSESSION_AVAILABLE: + configuration = \ + NSURLSessionConfiguration.defaultSessionConfiguration() + # set minumum supported TLS protocol (defaults to TLS1) + configuration.setTLSMinimumSupportedProtocol_( + self.minimum_tls_protocol) + + self.session = \ + NSURLSession.sessionWithConfiguration_delegate_delegateQueue_( + configuration, self, None) + self.task = self.session.dataTaskWithRequest_(request) + self.task.resume() + else: + self.connection = NSURLConnection.alloc().initWithRequest_delegate_( + request, self) def cancel(self): '''Cancel the connection''' if self.connection: - self.connection.cancel() + if NSURLSESSION_AVAILABLE: + self.session.invalidateAndCancel() + else: + self.connection.cancel() self.done = True def isDone(self): '''Check if the connection request is complete. As a side effect, - allow the delegates to work my letting the run loop run for a bit''' + allow the delegates to work by letting the run loop run for a bit''' if self.done: return self.done # let the delegates do their thing @@ -255,13 +323,8 @@ class Gurl(NSObject): new_dict[key.lower()] = value return new_dict - def connection_didFailWithError_(self, connection, error): - '''NSURLConnection delegate method - Sent when a connection fails to load its request successfully.''' - - # we don't actually use the connection argument, so - # pylint: disable=W0613 - + def recordError_(self, error): + '''Record any error info from completed connection/session''' self.error = error # If this was an SSL error, try to extract the SSL error code. if 'NSUnderlyingError' in error.userInfo(): @@ -270,13 +333,40 @@ class Gurl(NSObject): if ssl_code: self.SSLerror = (ssl_code, ssl_error_codes.get( ssl_code, 'Unknown SSL error')) + + def removeExpectedSizeFromStoredHeaders(self): + '''If a successful transfer, clear the expected size so we + don\'t attempt to resume the download next time''' + if str(self.status).startswith('2'): + # remove the expected-size from the stored headers + headers = self.get_stored_headers() + if 'expected-length' in headers: + del headers['expected-length'] + self.store_headers(headers) + + def URLSession_task_didCompleteWithError_(self, session, task, error): + '''NSURLSessionTaskDelegate method.''' + # we don't actually use the session or task arguments, so + # pylint: disable=W0613 + if self.destination and self.destination_path: + self.destination.close() + self.removeExpectedSizeFromStoredHeaders() + if error: + self.recordError_(error) + self.done = True + + def connection_didFailWithError_(self, connection, error): + '''NSURLConnectionDelegate method + Sent when a connection fails to load its request successfully.''' + # we don't actually use the connection argument, so + # pylint: disable=W0613 + self.recordError_(error) self.done = True if self.destination and self.destination_path: self.destination.close() - # delete it? Might not want to... def connectionDidFinishLoading_(self, connection): - '''NSURLConnectionDataDelegat delegate method + '''NSURLConnectionDataDelegate method Sent when a connection has finished loading successfully.''' # we don't actually use the connection argument, so @@ -285,18 +375,11 @@ class Gurl(NSObject): self.done = True if self.destination and self.destination_path: self.destination.close() - if str(self.status).startswith('2'): - # remove the expected-size from the stored headers - headers = self.get_stored_headers() - if 'expected-length' in headers: - del headers['expected-length'] - self.store_headers(headers) - - def connection_didReceiveResponse_(self, connection, response): - '''NSURLConnectionDataDelegate delegate method - Sent when the connection has received sufficient data to construct the - URL response for its request.''' + self.removeExpectedSizeFromStoredHeaders() + def handleResponse_withCompletionHandler_( + self, response, completionHandler): + '''Handle the response to the connection''' self.response = response self.bytesReceived = 0 self.percentComplete = -1 @@ -330,7 +413,12 @@ class Gurl(NSObject): # we have a partial for self.log( 'Can\'t resume download; file on server has changed.') - connection.cancel() + if completionHandler: + # tell the session task to cancel + completionHandler(NSURLSessionResponseCancel) + else: + # cancel the connection + self.connection.cancel() self.log('Removing %s' % self.destination_path) os.unlink(self.destination_path) # restart and attempt to download the entire file @@ -355,85 +443,107 @@ class Gurl(NSObject): # the downloadand for future checking if the file on the server # has changed self.store_headers(download_data) + if completionHandler: + # tell the session task to continue + completionHandler(NSURLSessionResponseAllow) - def connection_willSendRequest_redirectResponse_( - self, connection, request, response): + def URLSession_dataTask_didReceiveResponse_completionHandler_( + self, session, task, response, completionHandler): + '''NSURLSessionDataDelegate method''' + # we don't actually use the session or task arguments, so + # pylint: disable=W0613 + completionHandler.__block_signature__ = objc_method_signature('v@i') + self.handleResponse_withCompletionHandler_(response, completionHandler) + + def connection_didReceiveResponse_(self, connection, response): '''NSURLConnectionDataDelegate delegate method - Sent when the connection determines that it must change URLs in order to - continue loading a request.''' - + Sent when the connection has received sufficient data to construct the + URL response for its request.''' # we don't actually use the connection argument, so # pylint: disable=W0613 + self.handleResponse_withCompletionHandler_(response, None) + def handleRedirect_newRequest_withCompletionHandler_( + self, response, request, completionHandler): + '''Handle the redirect request''' if response == None: - # This isn't a real redirect, this is without talking to a server. - # Pass it back as-is - return request - # But if we're here, it appears to be a real redirect attempt + # the request has changed the NSURLRequest in order to standardize + # its format, for example, changing a request for + # http://www.apple.com to http://www.apple.com/. This occurs because + # the standardized, or canonical, version of the request is used for + # cache management. Pass the request back as-is + # (it appears that at some point Apple also defined a redirect like + # http://developer.apple.com to https://developer.apple.com to be + # 'merely' a change in the canonical URL.) + # Further -- it appears that this delegate method isn't called at + # all in this scenario, unlike NSConnectionDelegate method + # connection:willSendRequest:redirectResponse: + # we'll leave this here anyway in case we're wrong about that + if completionHandler: + completionHandler(request) + return + else: + return request + # If we get here, it appears to be a real redirect attempt # Annoyingly, we apparently can't get access to the headers from the # site that told us to redirect. All we know is that we were told # to redirect and where the new location is. newURL = request.URL().absoluteString() self.redirection.append([newURL, dict(response.allHeaderFields())]) newParsedURL = urlparse(newURL) - # This code was largely based on the work of Andreas Fuchs + # This code was largely based on the work of Andreas Fuchs # (https://github.com/munki/munki/pull/465) if self.follow_redirects == True or self.follow_redirects == 'all': # Allow the redirect self.log('Allowing redirect to: %s' % newURL) - return request - elif self.follow_redirects == 'https' and newParsedURL.scheme == 'https': + if completionHandler: + completionHandler(request) + return + else: + return request + elif (self.follow_redirects == 'https' + and newParsedURL.scheme == 'https'): # Once again, allow the redirect self.log('Allowing redirect to: %s' % newURL) - return request + if completionHandler: + completionHandler(request) + return + else: + return request else: # If we're down here either the preference was set to 'none', # the url we're forwarding on to isn't https or follow_redirects # was explicitly set to False self.log('Denying redirect to: %s' % newURL) - return None + if completionHandler: + completionHandler(None) + return + else: + return None - def connection_willSendRequestForAuthenticationChallenge_( - self, connection, challenge): - '''NSURLConnection delegate method - Tells the delegate that the connection will send a request for an - authentication challenge. - New in 10.7.''' + def URLSession_task_willPerformHTTPRedirection_newRequest_completionHandler_( + self, session, task, response, request, completionHandler): + '''NSURLSessionTaskDelegate method''' + # we don't actually use the session or task arguments, so + # pylint: disable=W0613 + self.log( + 'URLSession_task_willPerformHTTPRedirection_newRequest_' + 'completionHandler_') + completionHandler.__block_signature__ = objc_method_signature('v@@') + self.handleRedirect_newRequest_withCompletionHandler_( + response, request, completionHandler) + + def connection_willSendRequest_redirectResponse_( + self, connection, request, response): + '''NSURLConnectionDataDelegate method + Sent when the connection determines that it must change URLs in order to + continue loading a request.''' # we don't actually use the connection argument, so # pylint: disable=W0613 - - self.log('connection_willSendRequestForAuthenticationChallenge_') - protectionSpace = challenge.protectionSpace() - host = protectionSpace.host() - realm = protectionSpace.realm() - authenticationMethod = protectionSpace.authenticationMethod() - self.log( - 'Authentication challenge for Host: %s Realm: %s AuthMethod: %s' - % (host, realm, authenticationMethod)) - if challenge.previousFailureCount() > 0: - # we have the wrong credentials. just fail - self.log('Previous authentication attempt failed.') - challenge.sender().cancelAuthenticationChallenge_(challenge) - if self.username and self.password and authenticationMethod in [ - 'NSURLAuthenticationMethodDefault', - 'NSURLAuthenticationMethodHTTPBasic', - 'NSURLAuthenticationMethodHTTPDigest']: - self.log('Will attempt to authenticate.') - self.log('Username: %s Password: %s' - % (self.username, ('*' * len(self.password or '')))) - credential = ( - NSURLCredential.credentialWithUser_password_persistence_( - self.username, self.password, - NSURLCredentialPersistenceNone)) - challenge.sender().useCredential_forAuthenticationChallenge_( - credential, challenge) - else: - # fall back to system-provided default behavior - self.log('Allowing OS to handle authentication request') - challenge.sender( - ).performDefaultHandlingForAuthenticationChallenge_( - challenge) + self.log('connection_willSendRequest_redirectResponse_') + return self.handleRedirect_newRequest_withCompletionHandler_( + response, request, None) def connection_canAuthenticateAgainstProtectionSpace_( self, connection, protectionSpace): @@ -464,17 +574,9 @@ class Gurl(NSObject): self.log('Allowing OS to handle authentication request') return False - def connection_didReceiveAuthenticationChallenge_( - self, connection, challenge): - '''NSURLConnection delegate method - Sent when a connection must authenticate a challenge in order to - download its request. - Deprecated in 10.10''' - - # we don't actually use the connection argument, so - # pylint: disable=W0613 - - self.log('connection_didReceiveAuthenticationChallenge_') + def handleChallenge_withCompletionHandler_( + self, challenge, completionHandler): + '''Handle an authentication challenge''' protectionSpace = challenge.protectionSpace() host = protectionSpace.host() realm = protectionSpace.realm() @@ -485,7 +587,12 @@ class Gurl(NSObject): if challenge.previousFailureCount() > 0: # we have the wrong credentials. just fail self.log('Previous authentication attempt failed.') - challenge.sender().cancelAuthenticationChallenge_(challenge) + if completionHandler: + completionHandler( + NSURLSessionAuthChallengeCancelAuthenticationChallenge, + None) + else: + challenge.sender().cancelAuthenticationChallenge_(challenge) if self.username and self.password and authenticationMethod in [ 'NSURLAuthenticationMethodDefault', 'NSURLAuthenticationMethodHTTPBasic', @@ -497,22 +604,65 @@ class Gurl(NSObject): NSURLCredential.credentialWithUser_password_persistence_( self.username, self.password, NSURLCredentialPersistenceNone)) - challenge.sender().useCredential_forAuthenticationChallenge_( - credential, challenge) + if completionHandler: + completionHandler( + NSURLSessionAuthChallengeUseCredential, credential) + else: + challenge.sender().useCredential_forAuthenticationChallenge_( + credential, challenge) else: # fall back to system-provided default behavior - self.log('Continuing without credential.') - challenge.sender( - ).continueWithoutCredentialForAuthenticationChallenge_( - challenge) - - def connection_didReceiveData_(self, connection, data): - '''NSURLConnectionDataDelegate method - Sent as a connection loads data incrementally''' + self.log('Allowing OS to handle authentication request') + if completionHandler: + completionHandler( + NSURLSessionAuthChallengePerformDefaultHandling, None) + else: + if (challenge.sender().respondsToSelector_( + 'performDefaultHandlingForAuthenticationChallenge:')): + self.log('Allowing OS to handle authentication request') + challenge.sender( + ).performDefaultHandlingForAuthenticationChallenge_( + challenge) + else: + # Mac OS X 10.6 doesn't support + # performDefaultHandlingForAuthenticationChallenge: + self.log('Continuing without credential.') + challenge.sender( + ).continueWithoutCredentialForAuthenticationChallenge_( + challenge) + def connection_willSendRequestForAuthenticationChallenge_( + self, connection, challenge): + '''NSURLConnection delegate method + Tells the delegate that the connection will send a request for an + authentication challenge. New in 10.7.''' # we don't actually use the connection argument, so # pylint: disable=W0613 + self.log('connection_willSendRequestForAuthenticationChallenge_') + self.handleChallenge_withCompletionHandler_(challenge, None) + def URLSession_task_didReceiveChallenge_completionHandler_( + self, session, task, challenge, completionHandler): + '''NSURLSessionTaskDelegate method''' + # we don't actually use the session or task arguments, so + # pylint: disable=W0613 + completionHandler.__block_signature__ = objc_method_signature('v@i@') + self.log('URLSession_task_didReceiveChallenge_completionHandler_') + self.handleChallenge_withCompletionHandler_( + challenge, completionHandler) + + def connection_didReceiveAuthenticationChallenge_( + self, connection, challenge): + '''NSURLConnection delegate method + Sent when a connection must authenticate a challenge in order to + download its request. Deprecated in 10.10''' + # we don't actually use the connection argument, so + # pylint: disable=W0613 + self.log('connection_didReceiveAuthenticationChallenge_') + self.handleChallenge_withCompletionHandler_(challenge, None) + + def handleReceivedData_(self, data): + '''Handle received data''' if self.destination: self.destination.write(str(data)) else: @@ -521,3 +671,16 @@ class Gurl(NSObject): if self.expectedLength != NSURLResponseUnknownLength: self.percentComplete = int( float(self.bytesReceived)/float(self.expectedLength) * 100.0) + + def URLSession_dataTask_didReceiveData_(self, session, task, data): + '''NSURLSessionDataDelegate method''' + # we don't actually use the session or task arguments, so + # pylint: disable=W0613 + self.handleReceivedData_(data) + + def connection_didReceiveData_(self, connection, data): + '''NSURLConnectionDataDelegate method + Sent as a connection loads data incrementally''' + # we don't actually use the connection argument, so + # pylint: disable=W0613 + self.handleReceivedData_(data) From b92285ce7d6a8d2511e60fadf4e49b9153956b76 Mon Sep 17 00:00:00 2001 From: Nick McSpadden Date: Mon, 7 Mar 2016 18:44:40 -0800 Subject: [PATCH 02/29] Fixed some typos --- code/client/munkilib/appleupdates.py | 2 +- code/client/munkilib/removepackages.py | 2 +- code/client/munkilib/updatecheck.py | 8 ++++---- code/client/munkilib/utils.py | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/code/client/munkilib/appleupdates.py b/code/client/munkilib/appleupdates.py index ae395fb8..e920980b 100755 --- a/code/client/munkilib/appleupdates.py +++ b/code/client/munkilib/appleupdates.py @@ -1610,7 +1610,7 @@ class AppleUpdates(object): if key in metadata_to_copy and metadata[key]: if key == 'RestartAction': # Ensure that a heavier weighted 'RestartAction' is not - # overriden by one supplied in metadata + # overridden by one supplied in metadata if metadata[key] not in RestartActions.get( item.get(key, 'None')): munkicommon.display_debug2( diff --git a/code/client/munkilib/removepackages.py b/code/client/munkilib/removepackages.py index 20e50684..0dd9c67b 100755 --- a/code/client/munkilib/removepackages.py +++ b/code/client/munkilib/removepackages.py @@ -335,7 +335,7 @@ def ImportBom(bompath, curs): package database into our internal package database. """ # If we completely trusted the accuracy of Apple's database, we wouldn't - # need the bom files, but in my enviroment at least, the bom files are + # need the bom files, but in my environment at least, the bom files are # a better indicator of what flat packages have actually been installed # on the current machine. # We still need to consult Apple's package database diff --git a/code/client/munkilib/updatecheck.py b/code/client/munkilib/updatecheck.py index 306a5471..9d6548e8 100755 --- a/code/client/munkilib/updatecheck.py +++ b/code/client/munkilib/updatecheck.py @@ -1467,7 +1467,7 @@ def lookForUpdates(itemname, cataloglist): update_list = [] for catalogname in cataloglist: if not catalogname in CATALOG.keys(): - # in case the list refers to a non-existant catalog + # in case the list refers to a non-existent catalog continue updaters = CATALOG[catalogname]['updaters'] @@ -1925,7 +1925,7 @@ def processInstall(manifestitem, cataloglist, installinfo): iteminfo[key] = item_pl[key] if not 'apple_item' in iteminfo: - # admin did not explictly mark this item; let's determine if + # admin did not explicitly mark this item; let's determine if # it's from Apple if isAppleItem(item_pl): iteminfo['apple_item'] = True @@ -2368,7 +2368,7 @@ def processRemoval(manifestitem, cataloglist, installinfo): iteminfo[key] = uninstall_item[key] if not 'apple_item' in iteminfo: - # admin did not explictly mark this item; let's determine if + # admin did not explicitly mark this item; let's determine if # it's from Apple if isAppleItem(item_pl): iteminfo['apple_item'] = True @@ -2890,7 +2890,7 @@ def download_icons(item_list): def download_client_resources(): """Download client customization resources (if any).""" - # Munki's preferences can specify an explict name + # Munki's preferences can specify an explicit name # under ClientResourcesFilename # if that doesn't exist, use the primary manifest name as the # filename. If that fails, try site_default.zip diff --git a/code/client/munkilib/utils.py b/code/client/munkilib/utils.py index 8fa8b584..7164593e 100644 --- a/code/client/munkilib/utils.py +++ b/code/client/munkilib/utils.py @@ -21,7 +21,7 @@ Created by Justin McWilliams on 2010-10-26. Common utility functions used throughout Munki. -Note: this module should be 100% free of ObjC-dependant Python imports. +Note: this module should be 100% free of ObjC-dependent Python imports. """ From 4c8b71d03ec821e0b88cefd73aa2407d23d480dc Mon Sep 17 00:00:00 2001 From: Tim Morgan Date: Wed, 9 Mar 2016 12:45:57 -0800 Subject: [PATCH 03/29] [WIP] El Capitan-style CSS --- .../MSCDockTilePlugin/Info.plist | 2 +- .../project.pbxproj | 13 +- .../Managed Software Center-Info.plist | 42 ++--- .../WebResources/base.css | 151 ++++-------------- .../WebResources/detail.css | 4 +- .../WebResources/updates.css | 30 +--- .../templates/myitems_row_template.html | 8 +- 7 files changed, 72 insertions(+), 178 deletions(-) diff --git a/code/apps/Managed Software Center/MSCDockTilePlugin/Info.plist b/code/apps/Managed Software Center/MSCDockTilePlugin/Info.plist index 953fc50e..95a57eff 100644 --- a/code/apps/Managed Software Center/MSCDockTilePlugin/Info.plist +++ b/code/apps/Managed Software Center/MSCDockTilePlugin/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - com.googlecode.munki.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType diff --git a/code/apps/Managed Software Center/Managed Software Center.xcodeproj/project.pbxproj b/code/apps/Managed Software Center/Managed Software Center.xcodeproj/project.pbxproj index d5dcd75a..f4b9019a 100644 --- a/code/apps/Managed Software Center/Managed Software Center.xcodeproj/project.pbxproj +++ b/code/apps/Managed Software Center/Managed Software Center.xcodeproj/project.pbxproj @@ -34,7 +34,7 @@ C0B9E8B619AF7E9E00DB7247 /* Managed Software Center 10_6.icns in Resources */ = {isa = PBXBuildFile; fileRef = C0B9E8B519AF7E9E00DB7247 /* Managed Software Center 10_6.icns */; }; C0E098BC1857A3C80045DEEB /* msclib.py in Resources */ = {isa = PBXBuildFile; fileRef = C0E098BB1857A3C80045DEEB /* msclib.py */; }; C0EF96BA1ADDB9B2002C02FF /* DockTilePlugIn.m in Sources */ = {isa = PBXBuildFile; fileRef = C0EF96B91ADDB9B2002C02FF /* DockTilePlugIn.m */; }; - C0EF96BD1ADDBD88002C02FF /* MSCDockTilePlugin.docktileplugin in Copy Files */ = {isa = PBXBuildFile; fileRef = C0EF96B11ADDB90B002C02FF /* MSCDockTilePlugin.docktileplugin */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + C0EF96BD1ADDBD88002C02FF /* MSCDockTilePlugin.docktileplugin in Copy Files */ = {isa = PBXBuildFile; fileRef = C0EF96B11ADDB90B002C02FF /* MSCDockTilePlugin.docktileplugin */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; C0F1586E187D256200052F9A /* MyStuffTemplate.png in Resources */ = {isa = PBXBuildFile; fileRef = C0F1586D187D256200052F9A /* MyStuffTemplate.png */; }; /* End PBXBuildFile section */ @@ -335,7 +335,7 @@ isa = PBXProject; attributes = { CLASSPREFIX = MSC; - LastUpgradeCheck = 0510; + LastUpgradeCheck = 0720; ORGANIZATIONNAME = "The Munki Project"; TargetAttributes = { C0EF96B01ADDB90B002C02FF = { @@ -606,6 +606,7 @@ CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_OBJC_EXCEPTIONS = YES; @@ -649,7 +650,6 @@ C090050F16CDD84E00BE34CE /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; COMBINE_HIDPI_IMAGES = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Managed Software Center/Managed Software Center-Prefix.pch"; @@ -665,6 +665,7 @@ ); MACOSX_DEPLOYMENT_TARGET = 10.6; ONLY_ACTIVE_ARCH = NO; + PRODUCT_BUNDLE_IDENTIFIER = com.googlecode.munki.ManagedSoftwareCenter; PRODUCT_NAME = "Managed Software Center"; SDKROOT = macosx; WRAPPER_EXTENSION = app; @@ -674,7 +675,6 @@ C090051016CDD84E00BE34CE /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; COMBINE_HIDPI_IMAGES = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Managed Software Center/Managed Software Center-Prefix.pch"; @@ -689,6 +689,7 @@ "$(SYSTEM_LIBRARY_DIR)/Frameworks/Python.framework/Versions/2.6/lib/python2.6/config", ); MACOSX_DEPLOYMENT_TARGET = 10.6; + PRODUCT_BUNDLE_IDENTIFIER = com.googlecode.munki.ManagedSoftwareCenter; PRODUCT_NAME = "Managed Software Center"; SDKROOT = macosx; WRAPPER_EXTENSION = app; @@ -698,7 +699,6 @@ C0EF96B61ADDB90B002C02FF /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = NO; CLANG_WARN_BOOL_CONVERSION = YES; @@ -731,6 +731,7 @@ "-framework", AppKit, ); + PRODUCT_BUNDLE_IDENTIFIER = "com.googlecode.munki.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; SKIP_INSTALL = NO; @@ -741,7 +742,6 @@ C0EF96B71ADDB90B002C02FF /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = NO; CLANG_WARN_BOOL_CONVERSION = YES; @@ -770,6 +770,7 @@ "-framework", AppKit, ); + PRODUCT_BUNDLE_IDENTIFIER = "com.googlecode.munki.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; SKIP_INSTALL = NO; diff --git a/code/apps/Managed Software Center/Managed Software Center/Managed Software Center-Info.plist b/code/apps/Managed Software Center/Managed Software Center/Managed Software Center-Info.plist index ab2dd430..b8352066 100644 --- a/code/apps/Managed Software Center/Managed Software Center/Managed Software Center-Info.plist +++ b/code/apps/Managed Software Center/Managed Software Center/Managed Software Center-Info.plist @@ -2,22 +2,16 @@ - NSUserNotificationAlertStyle - alert - NSDockTilePlugIn - MSCDockTilePlugin.docktileplugin - CFBundleDisplayName - ${PRODUCT_NAME} - LSHasLocalizedDisplayName - CFBundleDevelopmentRegion en + CFBundleDisplayName + ${PRODUCT_NAME} CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFile ${EXECUTABLE_NAME} CFBundleIdentifier - com.googlecode.munki.ManagedSoftwareCenter + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName @@ -28,18 +22,6 @@ 4.1 CFBundleSignature ???? - CFBundleVersion - 1 - GitRevision - - LSMinimumSystemVersion - ${MACOSX_DEPLOYMENT_TARGET} - NSHumanReadableCopyright - Copyright © 2015 The Munki Project https://github.com/munki/munki - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication CFBundleURLTypes @@ -51,5 +33,23 @@ + CFBundleVersion + 1 + GitRevision + + LSHasLocalizedDisplayName + + LSMinimumSystemVersion + ${MACOSX_DEPLOYMENT_TARGET} + NSDockTilePlugIn + MSCDockTilePlugin.docktileplugin + NSHumanReadableCopyright + Copyright © 2015 The Munki Project https://github.com/munki/munki + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + NSUserNotificationAlertStyle + alert diff --git a/code/apps/Managed Software Center/Managed Software Center/WebResources/base.css b/code/apps/Managed Software Center/Managed Software Center/WebResources/base.css index c99f9fbe..e285686c 100644 --- a/code/apps/Managed Software Center/Managed Software Center/WebResources/base.css +++ b/code/apps/Managed Software Center/Managed Software Center/WebResources/base.css @@ -223,8 +223,8 @@ a { html, body { -webkit-background-size: 36px 635px; background-repeat: repeat-x; - background-color: #f5f6f7; - font-family: "Lucida Grande", Helvetica, sans-serif; + background-color: white; + font-family: Helvetica, sans-serif; font-size: 11px } @@ -276,7 +276,7 @@ div.columns { .sidebar { width: 200px; - margin-left: 15px + margin-left: 26px; } .sidebar h1, .main>h1 { @@ -286,13 +286,12 @@ div.columns { color: transparent; font-family: Helvetica; font-size: 24px; - font-weight: bold; + font-weight: normal; line-height: 26px; margin-bottom: 5px; overflow: visible; position: relative; - text-shadow: rgba(255, 255, 255, .496094) 0 1px 2px; - top: -5px + top: -5px; } footer { @@ -324,7 +323,6 @@ footer div.bottom-links * { color: #4f5f6e; font-size: 10px; font-weight: normal; - text-shadow: #fff 0 1px 0 } footer div.bottom-links>span { @@ -333,7 +331,7 @@ footer div.bottom-links>span { footer div.bottom-links li a { color: #576982; - font-weight: bold + font-weight: normal } footer div.bottom-links>ul>li:not(:last-child):after { @@ -443,19 +441,14 @@ div.select:after { } div.titled-box { - background-color: #fff; margin-bottom: 15px; padding-bottom: 10px; -webkit-border-radius: 5px; - -webkit-box-shadow: rgba(0, 0, 0, .45) 0 1px 3px, rgba(0, 0, 0, .8) 0 0 1px; - box-shadow: rgba(0, 0, 0, .45) 0 1px 4px, rgba(0, 0, 0, .2) 0 0 1px; - -webkit-background-clip: padding } div.titled-box h2 { - font: bold 13px 'Lucida Grande'; + font: normal 14px 'Helvetica'; color: #53565e; - padding: 0 10px; line-height: 24px; overflow: hidden; text-overflow: ellipsis; @@ -463,9 +456,9 @@ div.titled-box h2 { } div.titled-box h2 a { - font: bold 12px 'Lucida Grande'; + font: normal 12px 'Helvetica'; color: #53565e; - line-height: 25px + line-height: 24px } div.titled-box>div.content { @@ -477,11 +470,11 @@ div.titled-box.quick-links>div.content { } div.titled-box h2, div.titled-box hr { - border-width: 0 0 3px 0; + border: none; } div.titled-box hr { - margin: 8px 0 + margin: 28px 0 } div.titled-box li.popup { @@ -507,7 +500,7 @@ div.titled-box li.link { padding: 0 11px; height: 19px; line-height: 16px; - font-weight: bold; + font-weight: normal; border-color: transparent; border-width: 1px 0; border-style: solid @@ -523,7 +516,7 @@ div.titled-box li.link.selected { div.titled-box li.link a { display: block; font-size: 11px; - font-weight: bold; + font-weight: normal; color: #222; overflow: hidden; text-overflow: ellipsis; @@ -539,32 +532,24 @@ body.screen-reader div.chart ol>li div.lockup div.lockup-info>div.multi-button { } div.lockup-container, div.container, div.titled-container { - background-color: #fff; -webkit-border-radius: 5px; - -webkit-box-shadow: rgba(0, 0, 0, .45) 0 1px 3px, rgba(0, 0, 0, .8) 0 0 1px; - box-shadow: rgba(0, 0, 0, .45) 0 1px 4px, rgba(0, 0, 0, .2) 0 0 1px; - -webkit-background-clip: padding } div.lockup-container .title, div.titled-container .title { - padding: 0 10px; height: 32px; border-bottom: 1px solid #d7d7d7 } div.lockup-container .title h2, div.titled-container .title h2 { display: inline-block; - font: bold 14px 'Lucida Grande'; + font: normal 14px 'Helvetica'; color: #53565e; - padding: 0 10px 0 0; line-height: 32px } -div.lockup-container .title, div.titled-container .title, div.titled-box h2 { - text-shadow: 0 1px 0 #fff; +div.lockup-container .title, div.titled-container .title, div.titled-box h2 {; -webkit-border-top-left-radius: 5px; -webkit-border-top-right-radius: 5px; - background: -webkit-gradient(linear, left bottom, left top, from( #e3e3e3), color-stop(0.49, #ededed), color-stop(0.5, #f4f4f4), to(#fff)) } div.titled-box h2 { @@ -572,14 +557,16 @@ div.titled-box h2 { border-bottom: 1px solid #cacaca; border-width: 0 0 1px !important; margin-bottom: 6px; - -webkit-border-image: none + margin-top: 10px; + -webkit-border-image: none; + font-size: 13px; + line-height: 22px } div.lockup-container .title h1 { display: inline-block; - font: bold 14px Lucida Grande; + font: normal 14px Helvetica; color: #53565e; - padding: 0 10px 0 0; line-height: 32px } @@ -591,7 +578,7 @@ div.lockup-container .title h1 a { div.lockup-container .title span { color: #53565e; font-size: 10px; - font-weight: bold + font-weight: normal } div.lockup-container .content-and-controls, div.titled-container .content-and-controls { @@ -604,7 +591,6 @@ div.lockup-container .content-and-controls:before, div.titled-container .content position: absolute; width: 100%; top: -1px; - border-width: 0 0 3px 0; } div.lockup-container .content-and-controls:after, div.titled-container .content-and-controls:before { @@ -623,9 +609,6 @@ div.lockup-container div.lockup { float: left; width: 33.3%; height: 98px; - border-right: 1px solid #d9d9d9; - border-bottom: 1px solid #d9d9d9; - border-left: 1px solid #fff } div.lockup-container div.lockup div.artwork { @@ -673,18 +656,6 @@ div.lockup-container[data-columns-current="3"] div.lockup:nth-of-type(3n+2) { width: 33.4% } -div.lockup-container[data-columns-current="3"] div.lockup:nth-of-type(6n+1), -div.lockup-container[data-columns-current="3"] div.lockup:nth-of-type(6n+2), -div.lockup-container[data-columns-current="3"] div.lockup:nth-of-type(6n+3) { - background: #fff -} - -div.lockup-container[data-columns-current="3"] div.lockup:nth-of-type(6n+4), -div.lockup-container[data-columns-current="3"] div.lockup:nth-of-type(6n+5), -div.lockup-container[data-columns-current="3"] div.lockup:nth-of-type(6n+6) { - background: -webkit-gradient(linear, left top, left bottom, from( #f3f3f3), to( #eaeaea)) -} - div.lockup-container[data-columns-current="3"] div.lockup:nth-of-type(3n+1) { border-left: 0 } @@ -693,43 +664,16 @@ div.lockup-container:not(.shelf)[data-columns-current="3"] div.lockup:nth-of-typ display: table-cell; /*float: none;*/ /*height: auto;*/ - border-right: 0; } div.lockup-container[data-columns-current="3"] div.lockup:nth-last-of-type(3) { -webkit-border-bottom-left-radius: 5px } -div.lockup-container[data-columns-current="4"] div.lockup:nth-of-type(8n+1), -div.lockup-container[data-columns-current="4"] div.lockup:nth-of-type(8n+2), -div.lockup-container[data-columns-current="4"] div.lockup:nth-of-type(8n+3), -div.lockup-container[data-columns-current="4"] div.lockup:nth-of-type(8n+4) { - background: #fff -} - -div.lockup-container[data-columns-current="4"] div.lockup:nth-of-type(8n+5), -div.lockup-container[data-columns-current="4"] div.lockup:nth-of-type(8n+6), -div.lockup-container[data-columns-current="4"] div.lockup:nth-of-type(8n+7), -div.lockup-container[data-columns-current="4"] div.lockup:nth-of-type(8n+8) { - background: -webkit-gradient(linear, left top, left bottom, from( #f3f3f3), to( #eaeaea)) -} - div.lockup-container[data-columns-current="4"] div.lockup, div.lockup-container[data-columns-current="4"] div.lockup:nth-of-type(3n+2) { width: 25% } -div.lockup-container[data-columns-current="4"] div.lockup:nth-of-type(3n+1) { - border-left: 1px solid #fff -} - -div.lockup-container[data-columns-current="4"] div.lockup:nth-of-type(3n) { - border-right: 1px solid #d9d9d9 -} - -div.lockup-container[data-columns-current="4"] div.lockup:nth-of-type(4n+1) { - border-left: 0 -} - div.lockup-container:not(.shelf)[data-columns-current="4"] div.lockup:nth-of-type(4n) { display: table-cell; /*float: none; @@ -749,41 +693,10 @@ div.lockup-container[data-columns-current="5"] div.lockup, div.lockup-container[ width: 20% } -div.lockup-container[data-columns-current="5"] div.lockup:nth-of-type(10n+1), -div.lockup-container[data-columns-current="5"] div.lockup:nth-of-type(10n+2), -div.lockup-container[data-columns-current="5"] div.lockup:nth-of-type(10n+3), -div.lockup-container[data-columns-current="5"] div.lockup:nth-of-type(10n+4), -div.lockup-container[data-columns-current="5"] div.lockup:nth-of-type(10n+5) { - background: #fff -} - -div.lockup-container[data-columns-current="5"] div.lockup:nth-of-type(10n+6), -div.lockup-container[data-columns-current="5"] div.lockup:nth-of-type(10n+7), -div.lockup-container[data-columns-current="5"] div.lockup:nth-of-type(10n+8), -div.lockup-container[data-columns-current="5"] div.lockup:nth-of-type(10n+9), -div.lockup-container[data-columns-current="5"] div.lockup:nth-of-type(10n+10) { - background: -webkit-gradient(linear, left top, left bottom, from( #f3f3f3), to( #eaeaea)) -} - -div.lockup-container[data-columns-current="5"] div.lockup:nth-of-type(3n+1), -div.lockup-container[data-columns-current="5"] div.lockup:nth-of-type(4n+1) { - border-left: 1px solid #fff -} - -div.lockup-container[data-columns-current="5"] div.lockup:nth-of-type(3n), -div.lockup-container[data-columns-current="5"] div.lockup:nth-of-type(4n) { - border-right: 1px solid #d9d9d9 -} - -div.lockup-container[data-columns-current="5"] div.lockup:nth-of-type(5n+1) { - border-left: 0 -} - div.lockup-container:not(.shelf)[data-columns-current="5"] div.lockup:nth-of-type(5n) { display: table-cell; /*float: none; height: auto;*/ - border-right: 0 } div.lockup-container[data-columns-current="5"] div.lockup:nth-last-of-type(5) { @@ -817,7 +730,6 @@ div.lockup ul li { div.lockup li.name { color: #000; - font-weight: bold; max-width: 190px } @@ -839,8 +751,7 @@ div.lockup-container div.lockup ul li { div.lockup-container div.lockup.category ul { margin-top: 6px; - font-weight: bold; - text-shadow: 0 1px 0 #fff + font-weight: normal; } div.lockup-container div.lockup.category li.genre a { @@ -853,13 +764,13 @@ div.msc-button.small { div.msc-button-inner { height: 13px; - -webkit-border-radius: 10px; - background: -webkit-gradient(linear, 0% 0, 0% 100%, from( #A8AAAF), color-stop(0.05, #A6A8AE), color-stop(0.5, #A1A3A9), color-stop(0.96, #9C9EA4), to( #989DA3)); + -webkit-border-radius: 3px; + background: -webkit-gradient(linear, 0% 0, 0% 100%, from(rgb(166, 168, 174)), to(rgb(157, 159, 164))); border: 1px solid rgba(136, 136, 138, .746094); text-transform: uppercase; /*text-shadow: rgba(0, 0, 0, .5) 0 -1px 0;*/ color: #fff; - font: normal normal bold 9px/11px 'Lucida Grande'; + font: normal normal bold 9px/12px 'Helvetica'; padding-left: 10px; padding-right: 10px; } @@ -878,7 +789,7 @@ div.msc-button-inner.removing { } div.msc-button-inner:not(.installed-not-removable):hover { - background: -webkit-gradient(linear, left top, left bottom, from( #85868d), color-stop(0.05, #84858c), color-stop(0.5, #888188), color-stop(0.96, #7b7c83), to( #7a7bb2)) + background: -webkit-gradient(linear, left top, left bottom, from( #85868d), to( #7a7bb2)) } div.msc-button button { @@ -901,11 +812,10 @@ div.msc-button-inner.large { font-size: 13px; font-family: "Helvetica"; text-transform: capitalize; - line-height: 24px; - border: 0; + line-height: 21px; + border: 1px solid rgb(42, 73, 118); color: #fff; - text-shadow: rgba(0, 0, 0, .5) 0 -1px 0; - background: -webkit-gradient(linear, left top, left bottom, from( #367FD4), color-stop(0.50, #2255A0), color-stop(0.49, #2B68B6), to( #234F92)); + background: -webkit-gradient(linear, left top, left bottom, from(rgb(73,124,205)), to(rgb(47,79,143))); border-color: #1F4A7A; -webkit-border-radius: 5px; } @@ -925,7 +835,7 @@ div.msc-button-inner.large.removing { } div.msc-button-inner.large:not(.installed-not-removable):hover { - background: -webkit-gradient(linear, left top, left bottom, from( #0067B8), color-stop(0.49, #00509A), color-stop(0.50, #003E85), to( #003777)) + background: -webkit-gradient(linear, left top, left bottom, from( #0067B8), to( #003777)) } div.msc-button.install-updates { @@ -1202,7 +1112,6 @@ div.showcase { overflow: hidden; -webkit-transition: opacity .25s; -webkit-border-bottom-right-radius: 8px; - -webkit-box-shadow: 0 1px 3px #999; position: relative; left: 0; margin-right: 0; diff --git a/code/apps/Managed Software Center/Managed Software Center/WebResources/detail.css b/code/apps/Managed Software Center/Managed Software Center/WebResources/detail.css index 3d3681e2..e59a33ca 100644 --- a/code/apps/Managed Software Center/Managed Software Center/WebResources/detail.css +++ b/code/apps/Managed Software Center/Managed Software Center/WebResources/detail.css @@ -63,7 +63,6 @@ font-size: 12px; line-height: 16px } body.product .sidebar .app-info .content { -padding: 0 10px; font-size: 11px; color: #000 } @@ -72,7 +71,7 @@ margin-bottom: 5px } body.product .sidebar .app-info li .label, body.product .sidebar .app-info p span.label { -font-weight: bold; +font-weight: normal; color: #787878 } body.product .sidebar .more-by { @@ -85,7 +84,6 @@ body.product .sidebar .more-by div.lockup { display: -webkit-box; padding: 7px 10px; border-width: 0 0 1px 0; -background-image: -webkit-gradient(linear,left top,left bottom,from(#fff),to( #f9f9f9)); height: 55px } body.product .sidebar .more-by div.lockup:last-child { diff --git a/code/apps/Managed Software Center/Managed Software Center/WebResources/updates.css b/code/apps/Managed Software Center/Managed Software Center/WebResources/updates.css index 279fc4da..0f38282f 100644 --- a/code/apps/Managed Software Center/Managed Software Center/WebResources/updates.css +++ b/code/apps/Managed Software Center/Managed Software Center/WebResources/updates.css @@ -41,19 +41,15 @@ div.installations table:not(.no-header):before { } div.installations thead { border-radius: 5px 5px 0 0; - padding: 0 0 0 10px; height: 32px; border-bottom: 1px solid #d7d7d7; - text-shadow: 0 1px 0 #fff; - background: -webkit-gradient(linear,left bottom,left top,from( #e3e3e3),color-stop(0.49, #ededed),color-stop(0.5, #f4f4f4),to(#fff)) } div.installations th { color: #53565e; font-size: 14px; - font-weight: bold; + font-weight: normal; height: 32px; line-height: 14px; - padding: 0 10px; text-align: left } #updates div.installations th { @@ -72,9 +68,6 @@ div.installations th:first-child { div.installations th:last-child { -webkit-border-top-right-radius: 5px } -div.installations tbody tr:nth-of-type(even) { - background: -webkit-gradient(linear,left top,left bottom,from( #f3f3f3),to( #eaeaea)) -} .installation td { border-top: 1px solid #fff; border-bottom: 1px solid #d9d9d9; @@ -83,6 +76,9 @@ div.installations tbody tr:nth-of-type(even) { .installation td,.installation td a { color: #494949 } +.installation td.install-info-cell,.installation td.install-info-cell a, li.install-info-cell { + color: rgb(121,121,121) +} .installation:first-child td { border-top: transparent } @@ -100,7 +96,7 @@ div.installations tbody tr:nth-of-type(even) { .installation h2 { color: #565656; font-size: 13px; - font-weight: bold; + font-weight: normal; overflow: hidden; text-overflow: ellipsis; max-width: 300px @@ -148,20 +144,12 @@ div.installations tbody tr:nth-of-type(even) { top: 6px; left: 0 } -#os-and-app-updates #os-updates:not(.hidden)+#app-updates tbody tr:nth-of-type(even) { - background: 0 -} -#os-and-app-updates #os-updates:not(.hidden)+#app-updates tbody tr:nth-of-type(odd) { - background: -webkit-gradient(linear,left top,left bottom,from( #f3f3f3),to( #eaeaea)) -} + @-webkit-keyframes fade-out-and-remove { 0% {opacity: 1} 100% {opacity: 0} } -#purchases { - text-shadow:#fff 0 1px 0 -} div.purchases .installation td { height: 41px } @@ -238,9 +226,8 @@ div.purchases .installation td.status span.preparing-removal } #updates #header h1 { font-size: 15px; - font-weight: bold; + font-weight: normal; color: #929292; - text-shadow: 0 1px 0 #fff; text-align: center } div.updates table { @@ -385,13 +372,12 @@ div.os-updates.expanded tbody tr:nth-child(n+3):before { top: 0; right: 100px; left: 240px; - background: -webkit-linear-gradient(left,rgba(0,0,0,.04) 0,rgba(0,0,0,.16) 20%,rgba(0,0,0,.16) 80%,rgba(0,0,0,.04) 100%) } div.os-updates.expanded tbody tr.sosumi:before { display: none } .activity-indicator { - font: bold 20px Helvetica + font: normal 20px Helvetica } #updates #header .scan-progress { padding: 0 0 1px 13px diff --git a/code/apps/Managed Software Center/Managed Software Center/templates/myitems_row_template.html b/code/apps/Managed Software Center/Managed Software Center/templates/myitems_row_template.html index 7e778308..4d9c42c0 100644 --- a/code/apps/Managed Software Center/Managed Software Center/templates/myitems_row_template.html +++ b/code/apps/Managed Software Center/Managed Software Center/templates/myitems_row_template.html @@ -7,12 +7,12 @@ - ${version_to_install} - ${size} - + ${version_to_install} + ${size} + ${status_text}