├── .gitignore ├── compareorgs ├── __init__.py ├── management │ ├── __init__.py │ ├── commands │ │ ├── __init__.py │ │ └── delete_jobs.py │ ├── __init__.pyc │ └── __pycache__ │ │ └── __init__.cpython-311.pyc ├── migrations │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-311.pyc │ │ └── 0001_initial.cpython-311.pyc │ └── 0001_initial.py ├── tests.py ├── __pycache__ │ ├── admin.cpython-311.pyc │ ├── forms.cpython-311.pyc │ ├── models.cpython-311.pyc │ ├── tasks.cpython-311.pyc │ ├── utils.cpython-311.pyc │ ├── views.cpython-311.pyc │ └── __init__.cpython-311.pyc ├── utils.py ├── forms.py ├── admin.py ├── models.py ├── views.py └── tasks.py ├── runtime.txt ├── sforgcompare ├── __init__.py ├── __pycache__ │ ├── urls.cpython-311.pyc │ ├── wsgi.cpython-311.pyc │ ├── __init__.cpython-311.pyc │ └── settings.cpython-311.pyc ├── asgi.py ├── wsgi.py ├── urls.py └── settings.py ├── db.sqlite3 ├── static ├── images │ ├── icon.png │ ├── logo.png │ ├── favicon.ico │ ├── i-icon.png │ ├── loading.gif │ ├── oh-dear.png │ ├── logo-small.png │ └── tquila-logo@1x.png ├── bootstrap │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.ttf │ │ └── glyphicons-halflings-regular.woff │ └── css │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap-theme.css.map │ │ └── bootstrap-theme.css ├── jquery-syntaxhighlighter │ ├── prettify │ │ ├── prettify.min.css │ │ └── prettify.min.js │ ├── styles │ │ ├── style.min.css │ │ └── theme-balupton.min.css │ └── jquery.syntaxhighlighter.min.js ├── js │ ├── main.js │ ├── compare-offline.js │ ├── jquery-migrate-1.1.0.min.js │ └── compare.js └── css │ └── styles.css ├── Procfile ├── templates ├── 500.html ├── logout.html ├── 404.html ├── loading.html ├── oauth_response.html ├── compare_results.html ├── base.html ├── compare_results_offline.html └── index.html ├── README.md ├── manage.py └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .pyc -------------------------------------------------------------------------------- /compareorgs/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.11.3 -------------------------------------------------------------------------------- /sforgcompare/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /compareorgs/management/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /compareorgs/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /compareorgs/management/commands/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/db.sqlite3 -------------------------------------------------------------------------------- /compareorgs/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /static/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/static/images/icon.png -------------------------------------------------------------------------------- /static/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/static/images/logo.png -------------------------------------------------------------------------------- /static/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/static/images/favicon.ico -------------------------------------------------------------------------------- /static/images/i-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/static/images/i-icon.png -------------------------------------------------------------------------------- /static/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/static/images/loading.gif -------------------------------------------------------------------------------- /static/images/oh-dear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/static/images/oh-dear.png -------------------------------------------------------------------------------- /static/images/logo-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/static/images/logo-small.png -------------------------------------------------------------------------------- /static/images/tquila-logo@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/static/images/tquila-logo@1x.png -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: gunicorn sforgcompare.wsgi --workers $WEB_CONCURRENCY 2 | worker: celery -A compareorgs.tasks worker -B --loglevel=info -------------------------------------------------------------------------------- /compareorgs/management/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/compareorgs/management/__init__.pyc -------------------------------------------------------------------------------- /compareorgs/__pycache__/admin.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/compareorgs/__pycache__/admin.cpython-311.pyc -------------------------------------------------------------------------------- /compareorgs/__pycache__/forms.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/compareorgs/__pycache__/forms.cpython-311.pyc -------------------------------------------------------------------------------- /compareorgs/__pycache__/models.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/compareorgs/__pycache__/models.cpython-311.pyc -------------------------------------------------------------------------------- /compareorgs/__pycache__/tasks.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/compareorgs/__pycache__/tasks.cpython-311.pyc -------------------------------------------------------------------------------- /compareorgs/__pycache__/utils.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/compareorgs/__pycache__/utils.cpython-311.pyc -------------------------------------------------------------------------------- /compareorgs/__pycache__/views.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/compareorgs/__pycache__/views.cpython-311.pyc -------------------------------------------------------------------------------- /sforgcompare/__pycache__/urls.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/sforgcompare/__pycache__/urls.cpython-311.pyc -------------------------------------------------------------------------------- /sforgcompare/__pycache__/wsgi.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/sforgcompare/__pycache__/wsgi.cpython-311.pyc -------------------------------------------------------------------------------- /compareorgs/__pycache__/__init__.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/compareorgs/__pycache__/__init__.cpython-311.pyc -------------------------------------------------------------------------------- /sforgcompare/__pycache__/__init__.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/sforgcompare/__pycache__/__init__.cpython-311.pyc -------------------------------------------------------------------------------- /sforgcompare/__pycache__/settings.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/sforgcompare/__pycache__/settings.cpython-311.pyc -------------------------------------------------------------------------------- /static/bootstrap/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/static/bootstrap/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /static/bootstrap/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/static/bootstrap/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /static/bootstrap/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/static/bootstrap/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /compareorgs/management/__pycache__/__init__.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/compareorgs/management/__pycache__/__init__.cpython-311.pyc -------------------------------------------------------------------------------- /compareorgs/migrations/__pycache__/__init__.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/compareorgs/migrations/__pycache__/__init__.cpython-311.pyc -------------------------------------------------------------------------------- /compareorgs/migrations/__pycache__/0001_initial.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sforgcompare/HEAD/compareorgs/migrations/__pycache__/0001_initial.cpython-311.pyc -------------------------------------------------------------------------------- /compareorgs/utils.py: -------------------------------------------------------------------------------- 1 | """ 2 | Utility class for various methods 3 | """ 4 | 5 | def chunks(l, n): 6 | """ 7 | Split a list into specified chunks 8 | """ 9 | n = max(1, n) 10 | return [l[i:i + n] for i in range(0, len(l), n)] -------------------------------------------------------------------------------- /compareorgs/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | class JobForm(forms.Form): 4 | org_one = forms.IntegerField(required=False) 5 | org_two = forms.IntegerField(required=False) 6 | api_choice = forms.CharField() 7 | email_choice = forms.CharField() 8 | email = forms.CharField() 9 | contextual_diff = forms.BooleanField(required=False, initial=True) -------------------------------------------------------------------------------- /templates/500.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block content %} 6 | 7 |
12 |
13 | 7 | Successfully logged out of Salesforce and Package Builder 8 |
9 | 10 | 11 | 12 | 13 | 18 | 19 | {% endblock %} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sforgcompare 2 | Django + Heroku application which compares metadata between two Salesforce environments and presents the differences 3 | 4 | ## Addons 5 | 6 | 1. Heroku Postgres 7 | 2. Heroku Redis 8 | 3. Heroku Scheduler (for clearing database) 9 | 10 | ## Config Variables 11 | 12 | 1. DEFAULT_FROM_EMAIL (eg. ben@edwards.nz) 13 | 2. EMAIL_HOST (eg. smtp.gmail.com) 14 | 3. EMAIL_HOST_PASSWORD 15 | 4. EMAIL_HOST_USER (eg. ben@edwards.nz) 16 | 5. EMAIL_PORT (eg. 587) 17 | 6. SALESFORCE_API_VERSION (eg. 39) 18 | 7. SALESFORCE_CONSUMER_KEY (from Salesforce Connected App) 19 | 8. SALESFORCE_CONSUMER_SECRET (from Salesforce Connected App) 20 | -------------------------------------------------------------------------------- /static/jquery-syntaxhighlighter/prettify/prettify.min.css: -------------------------------------------------------------------------------- 1 | .str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun{color:#660}.pln{color:#000}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec{color:#606}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}@media print{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun{color:#440}.pln{color:#000}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}} -------------------------------------------------------------------------------- /templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block content %} 6 | 7 |
12 |
13 | 9 | This tool uses the Salesforce Tooling or Metadata API (user selection) to compare metadata between two Orgs. This is useful when planning deployments or building deployment packages, as well as seeing what configuration exists in Production to Sandbox or between Sandbox environments. 10 |
11 |12 | None of your organisation information or data is captured or kept from running this tool. 13 |
14 | 15 |17 | Note: If you've selected to be emailed when the job is ready, you can close this window and visit the link in the email. 18 |
19 |
27 | 34 | This can take some time, depending on size of Orgs and API selection. 35 |
36 |' + metadata + ''); 69 | $content.syntaxHighlight(); 70 | $('#codeModalBody').html($content); 71 | $.SyntaxHighlighter.init(); 72 | } 73 | 74 | // Load modal 75 | $('#viewCodeModal').modal(); 76 | 77 | }); 78 | 79 | // Change display options 80 | $('#display_option').change(function() 81 | { 82 | $('tr.component').hide(); 83 | $('tr.type').show(); 84 | 85 | if ( $(this).val() == 'diff') 86 | { 87 | checkAnyChildVisible(); 88 | } 89 | else 90 | { 91 | $('#no_differences_message').hide(); 92 | } 93 | 94 | }); 95 | 96 | $('.loading-display').hide(); 97 | $('#compare_results').show(); 98 | checkAnyChildVisible(); 99 | 100 | }); 101 | 102 | // Check if the parent component type (eg ApexClass), has any children. If not, ApexClass won't display at all 103 | function checkAnyChildVisible() 104 | { 105 | // Loop through type rows 106 | $.each($('tr.type'), function() 107 | { 108 | var childVisible = false; 109 | 110 | // Loop through component rows 111 | $.each($('tr[class*="component_' + $(this).attr('class').split('_')[1] + '"]'), function() 112 | { 113 | // It a row is visible, this is enough to know to show the parent 114 | if ( !$(this).hasClass('success') ) 115 | { 116 | childVisible = true; 117 | return; 118 | } 119 | }); 120 | 121 | // If no children are visible, hide the parent 122 | if (!childVisible) 123 | { 124 | $(this).hide(); 125 | } 126 | 127 | }); 128 | 129 | var rowVisible = false; 130 | 131 | // Check that anything at all is visible 132 | $.each($('tr.type'), function() 133 | { 134 | if ($(this).is(':visible')) 135 | { 136 | rowVisible = true; 137 | return; 138 | } 139 | }); 140 | 141 | // If no rows are visible, display message 142 | if (!rowVisible) 143 | { 144 | $('#no_differences_message').show(); 145 | } 146 | 147 | } -------------------------------------------------------------------------------- /sforgcompare/settings.py: -------------------------------------------------------------------------------- 1 | import os 2 | import dj_database_url 3 | from pathlib import Path 4 | 5 | BASE_DIR = Path(__file__).resolve().parent.parent 6 | 7 | IS_HEROKU = "DYNO" in os.environ 8 | 9 | # SECURITY WARNING: keep the secret key used in production secret! 10 | SECRET_KEY = os.environ.get('SECRET_KEY', 'LOCAL') 11 | 12 | # SECURITY WARNING: don't run with debug turned on in production! 13 | DEBUG = os.environ.get('DEBUG') == '1' 14 | TEMPLATE_DEBUG = DEBUG 15 | THUMBNAIL_DEBUG = DEBUG 16 | 17 | ADMINS = ( 18 | ('Ben Edwards', 'ben@edwards.nz'), 19 | ) 20 | 21 | if IS_HEROKU: 22 | SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') 23 | SECURE_SSL_REDIRECT = True 24 | 25 | ALLOWED_HOSTS = ['*'] 26 | 27 | # Application definition 28 | 29 | INSTALLED_APPS = ( 30 | 'django.contrib.admin', 31 | 'django.contrib.auth', 32 | 'django.contrib.contenttypes', 33 | 'django.contrib.sessions', 34 | 'django.contrib.messages', 35 | 'django.contrib.staticfiles', 36 | 'compareorgs', 37 | 'storages', 38 | ) 39 | 40 | MIDDLEWARE = [ 41 | 'django.middleware.security.SecurityMiddleware', 42 | 'whitenoise.middleware.WhiteNoiseMiddleware', 43 | 'django.contrib.sessions.middleware.SessionMiddleware', 44 | 'django.middleware.common.CommonMiddleware', 45 | 'django.middleware.csrf.CsrfViewMiddleware', 46 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 47 | 'django.contrib.messages.middleware.MessageMiddleware', 48 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 49 | ] 50 | 51 | SECURE_CROSS_ORIGIN_OPENER_POLICY = None 52 | 53 | ROOT_URLCONF = 'sforgcompare.urls' 54 | 55 | TEMPLATES = [ 56 | { 57 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 58 | 'DIRS': [ 59 | BASE_DIR / 'templates' 60 | ], 61 | 'APP_DIRS': True, 62 | 'OPTIONS': { 63 | 'context_processors': [ 64 | 'django.template.context_processors.debug', 65 | 'django.template.context_processors.request', 66 | 'django.contrib.auth.context_processors.auth', 67 | 'django.contrib.messages.context_processors.messages', 68 | ], 69 | }, 70 | }, 71 | ] 72 | 73 | WSGI_APPLICATION = 'sforgcompare.wsgi.application' 74 | 75 | MAX_CONN_AGE = 600 76 | 77 | DATABASES = { 78 | 'default': { 79 | 'ENGINE': 'django.db.backends.sqlite3', 80 | 'NAME': BASE_DIR / 'db.sqlite3', 81 | } 82 | } 83 | 84 | if "DATABASE_URL" in os.environ: 85 | # Configure Django for DATABASE_URL environment variable. 86 | DATABASES["default"] = dj_database_url.config( 87 | conn_max_age=MAX_CONN_AGE, ssl_require=True) 88 | 89 | # Celery settings 90 | BROKER_POOL_LIMIT = 1 91 | 92 | # Internationalization 93 | # https://docs.djangoproject.com/en/1.6/topics/i18n/ 94 | 95 | LANGUAGE_CODE = 'en-gb' 96 | TIME_ZONE = 'UTC' 97 | USE_I18N = True 98 | USE_L10N = True 99 | USE_TZ = True 100 | 101 | 102 | STATIC_ROOT = BASE_DIR / "staticfiles" 103 | STATICFILES_DIRS = [ 104 | BASE_DIR / "static", 105 | ] 106 | STATIC_URL = 'static/' 107 | 108 | # SALESFORCE KEYS 109 | SALESFORCE_CONSUMER_KEY = os.environ.get('SALESFORCE_CONSUMER_KEY') 110 | SALESFORCE_CONSUMER_SECRET = os.environ.get('SALESFORCE_CONSUMER_SECRET') 111 | SALESFORCE_REDIRECT_URI = 'https://sforgcompare.herokuapp.com/oauth_response' 112 | SALESFORCE_API_VERSION = int(os.environ.get('SALESFORCE_API_VERSION', '55')) 113 | 114 | # AWS Settings 115 | AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID') 116 | AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY') 117 | AWS_STORAGE_BUCKET_NAME = os.environ.get('AWS_STORAGE_BUCKET_NAME') 118 | 119 | STORAGES = { 120 | "default": { 121 | "BACKEND": "storages.backends.s3boto3.S3Boto3Storage", 122 | }, 123 | "staticfiles": { 124 | "BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage", 125 | }, 126 | } 127 | 128 | # Mail Settings 129 | DEFAULT_FROM_EMAIL = os.environ.get('DEFAULT_FROM_EMAIL') 130 | EMAIL_HOST = os.environ.get('EMAIL_HOST') 131 | EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER') 132 | EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD') 133 | EMAIL_PORT = os.environ.get('EMAIL_PORT') 134 | EMAIL_USE_TLS = True 135 | 136 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' -------------------------------------------------------------------------------- /templates/compare_results.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block scripts %} 6 | 7 | 8 | 9 | {% endblock %} 10 | 11 | {% block content %} 12 | 13 |
17 | 24 | Shouldn't be long... 25 |
26 |34 | Your Org Compare results are presented below. Files are highlighted based on matches or differences. You can click on components to view the file and see highlighted differences within files. 35 |
36 |{{ org_left_username }} |
76 | {{ org_right_username }} |
77 |
|---|
90 | There are no differences between the Orgs selected. 91 |
92 |There was an error getting the metadata:
' + resp + '
>/div>'); 50 | } 51 | }); 52 | } 53 | // Otherwise obtain metadata for display 54 | else 55 | { 56 | $.ajax( 57 | { 58 | url: '/get_metadata/' + $(this).attr('id'), 59 | type: 'get', 60 | success: function(resp) 61 | { 62 | var metadata; 63 | if (componentType == 'ApexClass' || componentType == 'ApexTrigger' || componentType == 'classes' || componentType == 'triggers') 64 | { 65 | if (componentName.indexOf('meta.xml') != -1) 66 | { 67 | metadata = resp.replace(//g,'>') 69 | .replace(/\n/g, '' + metadata + ''); 84 | $content.syntaxHighlight(); 85 | $('#codeModalBody').html($content); 86 | $.SyntaxHighlighter.init(); 87 | }, 88 | failure: function(resp) 89 | { 90 | $('#codeModalBody').html('
There was an error getting the metadata:
' + resp + '
>/div>'); 91 | } 92 | }); 93 | } 94 | 95 | // Load modal 96 | $('#viewCodeModal').modal(); 97 | 98 | }); 99 | 100 | // Change display options 101 | $('#display_option').change(function() 102 | { 103 | $('tr.component').hide(); 104 | $('tr.type').show(); 105 | 106 | if ( $(this).val() == 'diff') 107 | { 108 | checkAnyChildVisible(); 109 | } 110 | else 111 | { 112 | $('#no_differences_message').hide(); 113 | } 114 | 115 | }); 116 | 117 | $('.loading-display').hide(); 118 | $('#compare_results').show(); 119 | checkAnyChildVisible(); 120 | 121 | }); 122 | 123 | // Check if the parent component type (eg ApexClass), has any children. If not, ApexClass won't display at all 124 | function checkAnyChildVisible() 125 | { 126 | // Loop through type rows 127 | $.each($('tr.type'), function() 128 | { 129 | var childVisible = false; 130 | 131 | // Loop through component rows 132 | $.each($('tr[class*="component_' + $(this).attr('class').split('_')[1] + '"]'), function() 133 | { 134 | // It a row is visible, this is enough to know to show the parent 135 | if ( !$(this).hasClass('success') ) 136 | { 137 | childVisible = true; 138 | return; 139 | } 140 | }); 141 | 142 | // If no children are visible, hide the parent 143 | if (!childVisible) 144 | { 145 | $(this).hide(); 146 | } 147 | 148 | }); 149 | 150 | var rowVisible = false; 151 | 152 | // Check that anything at all is visible 153 | $.each($('tr.type'), function() 154 | { 155 | if ($(this).is(':visible')) 156 | { 157 | rowVisible = true; 158 | return; 159 | } 160 | }); 161 | 162 | // If no rows are visible, display message 163 | if (!rowVisible) 164 | { 165 | $('#no_differences_message').show(); 166 | } 167 | 168 | } 169 | 170 | function startDownloadJob(file_url, job_id) { 171 | 172 | if (file_url != '' && file_url != null) { 173 | 174 | updateModal( 175 | 'File Ready For Download', 176 | '
113 | 120 | Shouldn't be long... 121 |
122 |129 | Your Org Compare results are presented below. Files are highlighted based on matches or differences. You can click on components to view the file and see highlighted differences within files. 130 |
131 | 132 |{{ org_left_username }} |
158 | {{ org_right_username }} |
159 |
|---|
172 | There are no differences between the Orgs selected. 173 |
174 |9 | This tool uses the Salesforce Tooling or Metadata API (user selection) to compare metadata between two Orgs. This is useful when planning deployments or building deployment packages, as well as seeing what configuration exists in Production to Sandbox or between Sandbox environments. 10 |
11 |12 | None of your organisation information or data is captured or kept from running this tool. 13 |
14 || 44 | 48 | | 49 |50 | 51 | 54 | | 55 |
| 91 | 95 | | 96 |97 | 98 | 101 | | 102 |