瀏覽代碼

10.3.9 release

Gaudenz Alder 6 年之前
父節點
當前提交
03464d1c4c

+ 5 - 0
ChangeLog

@@ -1,3 +1,8 @@
+08-MAR-2019: 10.3.9
+
+- Adds warning for Google Drive legacy files
+- Adds language menu in Atlas theme
+
 08-MAR-2019: 10.3.8
 
 - Fixes possible NPEs

+ 1 - 1
VERSION

@@ -1 +1 @@
-10.3.8
+10.3.9

+ 1 - 1
src/main/webapp/cache.manifest

@@ -1,7 +1,7 @@
 CACHE MANIFEST
 
 # THIS FILE WAS GENERATED. DO NOT MODIFY!
-# 03/08/2019 08:44 AM
+# 03/08/2019 06:31 PM
 
 app.html
 index.html?offline=1

二進制
src/main/webapp/images/sidebar-gcp2.png


文件差異過大導致無法顯示
+ 125 - 60
src/main/webapp/js/app.min.js


+ 47 - 0
src/main/webapp/js/diagramly/App.js

@@ -1022,6 +1022,53 @@ App.prototype.init = function()
 						this.updateUserElement();
 						this.restoreLibraries();
 						this.checkLicense();
+						
+						this.drive.checkRealtimeFiles(mxUtils.bind(this, function()
+						{
+							var day = new Date().getDay();
+							var isWeekend = (day === 6) || (day === 0);
+							
+							if (isWeekend || Math.random() > 0.8)
+							{
+								var footer = document.createElement('div');
+								footer.style.cssText = 'position:absolute;bottom:0px;max-width:90%;padding:10px;padding-right:26px;' +
+									'white-space:nowrap;left:50%;bottom:2px;';
+								footer.className = 'geStatusAlert';
+								
+								mxUtils.setPrefixedStyle(footer.style, 'transform', 'translate(-50%,110%)');
+								mxUtils.setPrefixedStyle(footer.style, 'transition', 'all 1s ease');
+								footer.style.whiteSpace = 'nowrap';
+								footer.innerHTML = '<a href="https://desk.draw.io/support/solutions/articles/16000092210" ' +
+									'target="_blank" style="display:inline;text-decoration:none;font-weight:700;font-size:13px;opacity:1;">' +
+									'<img src="' + this.editor.graph.warningImage.src + '" border="0" style="margin-top:-4px;margin-right:2px;" valign="middle"/>&nbsp;' +
+									'You need to take action to convert legacy files. Click here.&nbsp;' +
+									'<img src="' + this.editor.graph.warningImage.src + '" border="0" style="margin-top:-4px;margin-left:2px;" valign="middle"/></a>';
+								
+								var img = document.createElement('img');
+								
+								img.setAttribute('src', Dialog.prototype.closeImage);
+								img.setAttribute('title', mxResources.get('close'));
+								img.style.position = 'absolute';
+								img.style.cursor = 'pointer';
+								img.style.right = '10px';
+								img.style.top = '12px';
+	
+								footer.appendChild(img);
+	
+								mxEvent.addListener(img, 'click', mxUtils.bind(this, function()
+								{
+									footer.parentNode.removeChild(footer);
+									this.hideFooter();
+								}));
+								
+								document.body.appendChild(footer);
+								
+								window.setTimeout(mxUtils.bind(this, function()
+								{
+									mxUtils.setPrefixedStyle(footer.style, 'transform', 'translate(-50%,0%)');
+								}), 1500);
+							}
+						}));
 					}))
 					
 					// Notifies listeners of new client

+ 119 - 111
src/main/webapp/js/diagramly/DriveClient.js

@@ -2388,6 +2388,22 @@ DriveClient.prototype.jsonToCell = function(val, codec)
 	return cell;
 };
 
+/**
+ * Invokes the given function if the user has writeable realtime files
+ * that must be converted.
+ */
+DriveClient.prototype.checkRealtimeFiles = function(fn)
+{
+	this.executeRequest(gapi.client.drive.files.list({'maxResults': 1, 'q': 'mimeType=\'application/vnd.jgraph.mxfile.realtime\'',
+		'includeTeamDriveItems': true, 'supportsTeamDrives': true}), mxUtils.bind(this, function(res)
+	{
+		if (res != null && (res.nextPageToken != null || (res.items != null && res.items.length > 0)))
+		{
+			fn();
+		}
+	}));
+};
+
 /**
  * Converts all old realtime files. Invoke this using
  * https://www.draw.io/?mode=google&convert-realtime=1
@@ -2411,58 +2427,62 @@ DriveClient.prototype.convertRealtimeFiles = function()
 	{
 		this.checkToken(mxUtils.bind(this, function()
 		{
-			if (this.user != null)
+			var q = 'mimeType=\'application/vnd.jgraph.mxfile.realtime\'';
+			var convertDelay = 15000;
+			var convertedIds = {};
+			var converted = 0;
+			var failed = 0;
+			var counter = 0;
+			var total = 0;
+			
+			var done = mxUtils.bind(this, function()
 			{
-				var q = 'mimeType=\'application/vnd.jgraph.mxfile.realtime\'';
-				var convertDelay = 15000;
-				var convertedIds = {};
-				var converted = 0;
-				var failed = 0;
-				var counter = 0;
-				var total = 0;
+				this.ui.spinner.stop();
+				print('<br>Conversion complete. Successfully converted ' + converted + ' file(s).', true);
 				
-				var done = mxUtils.bind(this, function()
+				if (failed > 0)
 				{
-					this.ui.spinner.stop();
-					print('<br>Conversion complete. Successfully converted ' + converted + ' file(s).', true);
-					
-					if (failed > 0)
-					{
-						print(' Failed to convert ' + failed + ' file(s).<br><br><b>ACTION REQUIRED:</b><br><ul><li>Click ' +
-							'<a target="_blank" href="https://drive.google.com/drive/u/0/search?q=type:application/vnd.jgraph.mxfile.realtime">here</a> ' +
-							'to list all affected files</li><li>Open each file in turn by right-clicking the file and selecting open with draw.io</li>' +
-							'<li>Open each file in turn. When loaded, select File->Save</li></ul>');	
-					}
-					else
-					{
-						print('<br><br>This window can now be closed.')
-					}
-				});
-				
-				var totals = {'maxResults': 10000, 'q': q, 'includeTeamDriveItems': true, 'supportsTeamDrives': true};
+					print(' Failed to convert ' + failed + ' file(s).<br><br><b>ACTION REQUIRED:</b><br><ul><li>Click ' +
+						'<a target="_blank" href="https://drive.google.com/drive/u/0/search?q=type:application/vnd.jgraph.mxfile.realtime">here</a> ' +
+						'to list all affected files</li><li>Open each file in turn by right-clicking the file and selecting open with draw.io</li>' +
+						'<li>Open each file in turn. When loaded, select File->Save</li></ul>');	
+				}
+				else
+				{
+					print('<br><br>This window can now be closed.')
+				}
+			});
+			
+			var totals = {'maxResults': 10000, 'q': q, 'includeTeamDriveItems': true, 'supportsTeamDrives': true};
+			
+			this.executeRequest(gapi.client.drive.files.list(totals), mxUtils.bind(this, function(res)
+			{
+				this.ui.spinner.stop();
+				total = (res != null && res.items != null) ? res.items.length : 0;
 				
-				this.executeRequest(gapi.client.drive.files.list(totals), mxUtils.bind(this, function(res)
+				if (this.ui.spinner.spin(document.body, 'Converting ' + total + ' file(s)'))
 				{
-					this.ui.spinner.stop();
-					total = (res != null && res.items != null) ? res.items.length : 0;
-					
-					if (this.ui.spinner.spin(document.body, 'Converting ' + total + ' file(s)'))
+					print('Found ' + total + ' file(s). This will take up to ' + Math.ceil((total * convertDelay) / 60000) + ' minute(s). <b>Please do not close this window!</b><br>');
+
+					// Does not show picker if there are no folders in the root
+					var nextPage = mxUtils.bind(this, function(token, delay)
 					{
-						print('Found ' + total + ' file(s). This will take up to ' + Math.ceil((total * convertDelay) / 60000) + ' minute(s). <b>Please do not close this window!</b><br>');
-	
-						// Does not show picker if there are no folders in the root
-						var nextPage = mxUtils.bind(this, function(token, delay)
+						var query = {'maxResults': 1, 'q': q, 'includeTeamDriveItems': true, 'supportsTeamDrives': true};
+						
+						if (token != null)
 						{
-							var query = {'maxResults': 1, 'q': q, 'includeTeamDriveItems': true, 'supportsTeamDrives': true};
-							
-							if (token != null)
-							{
-								query.pageToken = token;
-							}
-							
-							this.executeRequest(gapi.client.drive.files.list(query), mxUtils.bind(this, function(res)
+							query.pageToken = token;
+						}
+						
+						this.executeRequest(gapi.client.drive.files.list(query), mxUtils.bind(this, function(res)
+						{
+							var doNextPage = mxUtils.bind(this, function()
 							{
-								var doNextPage = mxUtils.bind(this, function()
+								if (res.nextPageToken != null)
+								{
+									nextPage(res.nextPageToken);
+								}
+								else
 								{
 									if (res.nextPageToken != null)
 									{
@@ -2470,88 +2490,76 @@ DriveClient.prototype.convertRealtimeFiles = function()
 									}
 									else
 									{
-										if (res.nextPageToken != null)
-										{
-											nextPage(res.nextPageToken);
-										}
-										else
-										{
-											done();
-										}
+										done();
 									}
-								});
-								
-								if (res != null && (res.items == null || res.items.length == 0) &&
-									res.nextPageToken != null)
-								{
-									// Next page can still contain results, see
-									// https://stackoverflow.com/questions/23741845
-									nextPage(res.nextPageToken, 10000);
 								}
-								else if (res != null && res.items != null && res.items.length > 0)
+							});
+							
+							if (res != null && (res.items == null || res.items.length == 0) &&
+								res.nextPageToken != null)
+							{
+								// Next page can still contain results, see
+								// https://stackoverflow.com/questions/23741845
+								nextPage(res.nextPageToken, 10000);
+							}
+							else if (res != null && res.items != null && res.items.length > 0)
+							{
+								var fileId = res.items[0].id;
+								this.ui.spinner.stop();
+								counter++;
+								
+								if (this.ui.spinner.spin(document.body, 'Converting file ' + counter + ' of ' + total))
 								{
-									var fileId = res.items[0].id;
-									this.ui.spinner.stop();
-									counter++;
-									
-									if (this.ui.spinner.spin(document.body, 'Converting file ' + counter + ' of ' + total))
+									print('Converting ' + counter + ' of ' + total + ': "' + mxUtils.htmlEntities(res.items[0].title) +
+										'" (' + fileId + ')... ', true);
+		
+									window.setTimeout(mxUtils.bind(this, function()
 									{
-										print('Converting ' + counter + ' of ' + total + ': "' + mxUtils.htmlEntities(res.items[0].title) +
-											'" (' + fileId + ')... ', true);
-			
-										window.setTimeout(mxUtils.bind(this, function()
+										// Exits if same file is returned twice
+										if (convertedIds[fileId] == null)
 										{
-											// Exits if same file is returned twice
-											if (convertedIds[fileId] == null)
+											convertedIds[fileId] = true;
+				
+											this.getFile(fileId, mxUtils.bind(this, function(file)
 											{
-												convertedIds[fileId] = true;
-					
-												this.getFile(fileId, mxUtils.bind(this, function(file)
+												this.saveFile(file, null, mxUtils.bind(this, function()
 												{
-													this.saveFile(file, null, mxUtils.bind(this, function()
-													{
-														converted++;
-														print('<img src="' + Editor.checkmarkImage + '" border="0" valign="middle"/>');
-														doNextPage();
-													}), mxUtils.bind(this, function(err)
-													{
-														var msg = (err != null && err.error != null && err.error.message != null) ? err.error.message : '';
-														failed++;
-														print('<img src="' + this.ui.editor.graph.warningImage.src + '" border="0" valign="absmiddle"/> ' + msg);
-														doNextPage();
-													}));
-												}), mxUtils.bind(this, function(e)
+													converted++;
+													print('<img src="' + Editor.checkmarkImage + '" border="0" valign="middle"/>');
+													doNextPage();
+												}), mxUtils.bind(this, function(err)
 												{
 													var msg = (err != null && err.error != null && err.error.message != null) ? err.error.message : '';
 													failed++;
 													print('<img src="' + this.ui.editor.graph.warningImage.src + '" border="0" valign="absmiddle"/> ' + msg);
 													doNextPage();
 												}));
-											}
-											else
+											}), mxUtils.bind(this, function(e)
 											{
-												this.ui.spinner.stop();
-												print('Search returned duplicate file ' + fileId + '. Exiting.<br><br>This window can now be closed.');
-											}
-										}), (delay != null) ? delay : convertDelay)
-									}
-								}
-								else
-								{
-									done();
+												var msg = (err != null && err.error != null && err.error.message != null) ? err.error.message : '';
+												failed++;
+												print('<img src="' + this.ui.editor.graph.warningImage.src + '" border="0" valign="absmiddle"/> ' + msg);
+												doNextPage();
+											}));
+										}
+										else
+										{
+											this.ui.spinner.stop();
+											print('Search returned duplicate file ' + fileId + '. Exiting.<br><br>This window can now be closed.');
+										}
+									}), (delay != null) ? delay : convertDelay)
 								}
-							}));
-						});
-						
-						nextPage();
-					}
-				}));
-			}
-			else
-			{
-				this.ui.spinner.stop();
-				print('Not logged in. Exiting.<br><br>This window can now be closed.');
-			}
+							}
+							else
+							{
+								done();
+							}
+						}));
+					});
+					
+					nextPage();
+				}
+			}));
 		}));
 	}
 	else

+ 1 - 0
src/main/webapp/js/diagramly/EditorUi.js

@@ -10329,6 +10329,7 @@
 						{
 							this.buttonContainer.style.paddingRight = '12px';
 							this.buttonContainer.style.paddingTop = '12px';
+							this.buttonContainer.style.right = '25px';
 						}
 						else if (uiTheme != 'min')
 						{

+ 65 - 50
src/main/webapp/js/diagramly/Menus.js

@@ -743,63 +743,74 @@
 			})));
 
 			// Extends the menubar with the language menu
-			if (uiTheme != 'atlas')
+			var menusCreateMenuBar = Menus.prototype.createMenubar;
+			Menus.prototype.createMenubar = function(container)
 			{
-				var menusCreateMenuBar = Menus.prototype.createMenubar;
-				Menus.prototype.createMenubar = function(container)
+				var menubar = menusCreateMenuBar.apply(this, arguments);
+				
+				if (menubar != null)
 				{
-					var menubar = menusCreateMenuBar.apply(this, arguments);
+					var langMenu = this.get('language');
 					
-					if (menubar != null)
-					{
-						var langMenu = this.get('language');
+					if (langMenu != null)
+					{
+						var elt = menubar.addMenu('', langMenu.funct);
+						elt.setAttribute('title', mxResources.get('language'));
+						elt.style.width = '16px';
+						elt.style.paddingTop = '2px';
+						elt.style.paddingLeft = '4px';
+						elt.style.zIndex = '1';
+						elt.style.position = 'absolute';
+						elt.style.display = 'block';
+						elt.style.cursor = 'pointer';
+						elt.style.right = '17px';
 						
-						if (langMenu != null)
+						if (uiTheme == 'atlas')
+						{
+							elt.style.top = '6px';
+							elt.style.right = '15px';
+						}
+						else if (uiTheme == 'min')
 						{
-							var elt = menubar.addMenu('', langMenu.funct);
-							elt.setAttribute('title', mxResources.get('language'));
-							elt.style.width = '16px';
-							elt.style.paddingTop = '2px';
-							elt.style.paddingLeft = '4px';
-							elt.style.zIndex = '1';
-							elt.style.position = 'absolute';
 							elt.style.top = '2px';
-							elt.style.right = '17px';
-							elt.style.display = 'block';
-							elt.style.cursor = 'pointer';
+						}
+						else
+						{
+							elt.style.top = '0px';
+						}
+						
+						if (!mxClient.IS_VML)
+						{
+							var icon = document.createElement('div');
+							icon.style.backgroundImage = 'url(' + Editor.globeImage + ')';
+							icon.style.backgroundPosition = 'center center';
+							icon.style.backgroundRepeat = 'no-repeat';
+							icon.style.backgroundSize = '19px 19px';
+							icon.style.position = 'absolute';
+							icon.style.height = '19px';
+							icon.style.width = '19px';
+							icon.style.marginTop = '2px';
+							icon.style.zIndex = '1';
+							elt.appendChild(icon);
+							mxUtils.setOpacity(elt, 40);
 							
-							if (!mxClient.IS_VML)
-							{
-								var icon = document.createElement('div');
-								icon.style.backgroundImage = 'url(' + Editor.globeImage + ')';
-								icon.style.backgroundPosition = 'center center';
-								icon.style.backgroundRepeat = 'no-repeat';
-								icon.style.backgroundSize = '19px 19px';
-								icon.style.position = 'absolute';
-								icon.style.height = '19px';
-								icon.style.width = '19px';
-								icon.style.marginTop = '2px';
-								icon.style.zIndex = '1';
-								elt.appendChild(icon);
-								mxUtils.setOpacity(elt, 40);
-								
-								if (uiTheme == 'dark')
-								{
-									elt.style.filter = 'invert(100%)';
-								}
-							}
-							else
+							if (uiTheme == 'atlas' || uiTheme == 'dark')
 							{
-								elt.innerHTML = '<div class="geIcon geSprite geSprite-globe"/>';
+								elt.style.opacity = '0.85';
+								elt.style.filter = 'invert(100%)';
 							}
-							
-							document.body.appendChild(elt);
 						}
+						else
+						{
+							elt.innerHTML = '<div class="geIcon geSprite geSprite-globe"/>';
+						}
+						
+						document.body.appendChild(elt);
 					}
-	
-					return menubar;
-				};
-			}
+				}
+
+				return menubar;
+			};
 		}
 		
 		this.put('help', new Menu(mxUtils.bind(this, function(menu, parent)
@@ -2789,7 +2800,7 @@
 			{
 				var item = this.addMenuItem(menu, 'scratchpad', parent);
 				
-				if (!editorUi.isOffline() || mxClient.IS_CHROMEAPP)
+				if (!editorUi.isOffline() || mxClient.IS_CHROMEAPP || EditorUi.isElectronApp)
 				{
 					this.addLinkToItem(item, 'https://desk.draw.io/support/solutions/articles/16000042367');
 				}
@@ -2821,7 +2832,11 @@
 			if (typeof(MathJax) !== 'undefined')
 			{
 				var item = this.addMenuItem(menu, 'mathematicalTypesetting', parent);
-				this.addLinkToItem(item, 'https://desk.draw.io/support/solutions/articles/16000032875');
+				
+				if (!editorUi.isOffline() || mxClient.IS_CHROMEAPP || EditorUi.isElectronApp)
+				{
+					this.addLinkToItem(item, 'https://desk.draw.io/support/solutions/articles/16000032875');
+				}
 			}
 			
 			if (urlParams['embed'] != '1')
@@ -2940,7 +2955,7 @@
 					
 					var item = this.addMenuItem(menu, 'synchronize', parent);
 					
-					if (!editorUi.isOffline() || mxClient.IS_CHROMEAPP)
+					if (!editorUi.isOffline() || mxClient.IS_CHROMEAPP || EditorUi.isElectronApp)
 					{
 						this.addLinkToItem(item, 'https://desk.draw.io/support/solutions/articles/16000087947');
 					}
@@ -2971,7 +2986,7 @@
 						menu.addSeparator(parent);
 						var item = this.addMenuItem(menu, 'synchronize', parent);
 						
-						if (!editorUi.isOffline() || mxClient.IS_CHROMEAPP)
+						if (!editorUi.isOffline() || mxClient.IS_CHROMEAPP || EditorUi.isElectronApp)
 						{
 							this.addLinkToItem(item, 'https://desk.draw.io/support/solutions/articles/16000087947');
 						}

+ 1 - 1
src/main/webapp/js/diagramly/Minimal.js

@@ -1381,9 +1381,9 @@ EditorUi.initMinimalTheme = function()
 		        	elt.style.height = '24px';
 		        	elt.style.width = '24px';
 					elt.style.zIndex = '1';
-					elt.style.top = '11px';
 					elt.style.right = '8px';
 					elt.style.cursor = 'pointer';
+					elt.style.top = (urlParams['embed'] == '1') ? '13px' : '11px';
 					menubar.appendChild(elt);
 					langMenuElt = elt;
 				}

+ 252 - 3
src/main/webapp/js/diagramly/sidebar/Sidebar-GCP2.js

@@ -19,6 +19,7 @@
 		this.addGCP2DeveloperToolsPalette();
 		this.addGCP2ExpandedProductCardsPalette();
 		this.addGCP2ProductCardsPalette();
+		this.addGCP2GeneralIconsPalette();
 	};
 	
 	Sidebar.prototype.addGCP2PathsPalette = function()
@@ -33,7 +34,7 @@
 			this.createEdgeTemplateEntry(s + 'dashed=0;strokeColor=#9E9E9E;', 100, 0, '', 'Secondary Path', null, dt + 'secondary'),
 			this.createEdgeTemplateEntry(s + 'dashed=1;dashPattern=1 3;strokeColor=#9E9E9E;', 100, 0, '', 'Optional Secondary Path', null, dt + 'optional secondary'),
 			this.createEdgeTemplateEntry(s + 'strokeColor=#34A853;dashed=0;', 100, 0, '', 'Success Status', null, dt + 'success status'),
-			this.createEdgeTemplateEntry(s + 'strokeColor=#EA4335;dashed=0;', 100, 0, '', 'Failure Status', null, dt + 'failure status'),
+			this.createEdgeTemplateEntry(s + 'strokeColor=#EA4335;dashed=0;', 100, 0, '', 'Failure Status', null, dt + 'failure status')
 	 	];
 		
 		this.addPalette('gcp2Paths', 'GCP / Paths', false, mxUtils.bind(this, function(content)
@@ -255,8 +256,7 @@
 			    bg.insert(label6);
 			    
 			   	return sb.createVertexTemplateFromCells([bg], bg.geometry.width, bg.geometry.height, 'Markers');
-			}),
-
+			})
 	 	];
 		
 		this.addPalette('gcp2Zones', 'GCP / Zones', false, mxUtils.bind(this, function(content)
@@ -268,6 +268,255 @@
 		}));
 	};
 	
+	Sidebar.prototype.addGCP2GeneralIconsPalette = function()
+	{
+		var sb = this;
+		var s = 1;
+		var n = 'html=1;aspect=fixed;strokeColor=none;shadow=0;align=center;verticalAlign=top;fillColor=#3B8DF1;shape=mxgraph.gcp2.';
+		var dt = 'gcp google cloud platform general icons icon ';
+		var gn = 'mxgraph.gcp2';
+		var fns = [];
+		
+		var fns = [
+		    this.createVertexTemplateEntry(n + 'biomedical_trio', 
+		    		s * 100, s * 68, null, 'Biomedical Trio', null, null, this.getTagsForStencil(gn, '', dt + 'biomedical trio').join(' ')),
+		    this.createVertexTemplateEntry(n + 'biomedical_beaker', 
+		    		s * 69, s * 100, null, 'Biomedical Beaker', null, null, this.getTagsForStencil(gn, '', dt + 'biomedical beaker').join(' ')),
+		    this.createVertexTemplateEntry(n + 'biomedical_test_tube', 
+		    		s * 31, s * 100, null, 'Biomedical Test Tube', null, null, this.getTagsForStencil(gn, '', dt + 'biomedical test tube').join(' ')),
+		    this.createVertexTemplateEntry(n + 'check_available', 
+		    		s * 100, s * 87, null, 'Check Available', null, null, this.getTagsForStencil(gn, '', dt + 'check available').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_monitoring', 
+		    		s * 90, s * 100, null, 'Cloud Monitoring', null, null, this.getTagsForStencil(gn, '', dt + 'cloud monitoring').join(' ')),
+		    this.createVertexTemplateEntry(n + 'repository', 
+		    		s * 60, s * 100, null, 'Repository', null, null, this.getTagsForStencil(gn, '', dt + 'repository').join(' ')),
+		    this.createVertexTemplateEntry(n + 'compute_engine_2', 
+		    		s * 54, s * 100, null, 'Compute Engine', null, null, this.getTagsForStencil(gn, '', dt + 'compute engine').join(' ')),
+		    this.createVertexTemplateEntry(n + 'capabilities', 
+		    		s * 100, s * 76, null, 'Capabilities', null, null, this.getTagsForStencil(gn, '', dt + 'capabilities thumbs up gear').join(' ')),
+		    this.createVertexTemplateEntry(n + 'globe_world', 
+		    		s * 100, s * 95, null, 'World Network', null, null, this.getTagsForStencil(gn, '', dt + 'globe global world network upload anywhere').join(' ')),
+		    this.createVertexTemplateEntry(n + 'process', 
+		    		s * 84, s * 100, null, 'Process', null, null, this.getTagsForStencil(gn, '', dt + 'process').join(' ')),
+		    this.createVertexTemplateEntry(n + 'arrow_cycle', 
+		    		s * 100, s * 95, null, 'Arrow Cycle', null, null, this.getTagsForStencil(gn, '', dt + 'arrow cycle').join(' ')),
+		    this.createVertexTemplateEntry(n + 'arrows_system', 
+		    		s * 100, s * 95, null, 'Arrows System', null, null, this.getTagsForStencil(gn, '', dt + 'arrows system').join(' ')),
+		    this.createVertexTemplateEntry(n + 'half_cloud', 
+		    		s * 100, s * 50, null, 'Half Cloud', null, null, this.getTagsForStencil(gn, '', dt + 'half cloud').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud', 
+		    		s * 100, s * 69, null, 'Cloud', null, null, this.getTagsForStencil(gn, '', dt + 'cloud').join(' ')),
+		    this.createVertexTemplateEntry(n + 'speed', 
+		    		s * 100, s * 57, null, 'Speed', null, null, this.getTagsForStencil(gn, '', dt + 'speed').join(' ')),
+		    this.createVertexTemplateEntry(n + 'time_clock', 
+		    		s * 86, s * 100, null, 'Overtime', null, null, this.getTagsForStencil(gn, '', dt + 'time clock frozen cold overtime').join(' ')),
+		    this.createVertexTemplateEntry(n + 'loading', 
+		    		s * 100, s * 100, null, 'Loading', null, null, this.getTagsForStencil(gn, '', dt + 'loading').join(' ')),
+		    this.createVertexTemplateEntry(n + 'clock', 
+		    		s * 100, s * 100, null, 'Clock', null, null, this.getTagsForStencil(gn, '', dt + 'clock').join(' ')),
+		    this.createVertexTemplateEntry(n + 'check', 
+		    		s * 100, s * 80, null, 'Check', null, null, this.getTagsForStencil(gn, '', dt + 'check').join(' ')),
+		    this.createVertexTemplateEntry('html=1;aspect=fixed;strokeColor=none;shadow=0;align=center;verticalAlign=top;fillColor=#F4AF20;shape=mxgraph.gcp2.check', 
+		    		s * 100, s * 80, null, 'Check (yellow)', null, null, this.getTagsForStencil(gn, '', dt + 'check').join(' ')),
+		    this.createVertexTemplateEntry('html=1;aspect=fixed;strokeColor=none;shadow=0;align=center;verticalAlign=top;fillColor=#2D9C5E;shape=mxgraph.gcp2.check', 
+		    		s * 100, s * 80, null, 'Check (green)', null, null, this.getTagsForStencil(gn, '', dt + 'check').join(' ')),
+		    this.createVertexTemplateEntry(n + 'lock', 
+		    		s * 78, s * 100, null, 'Lock', null, null, this.getTagsForStencil(gn, '', dt + 'lock').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_security', 
+		    		s * 100, s * 70, null, 'Cloud Security', null, null, this.getTagsForStencil(gn, '', dt + 'cloud security').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_checkmark', 
+		    		s * 100, s * 67, null, 'Cloud Checkmark', null, null, this.getTagsForStencil(gn, '', dt + 'cloud checkmark').join(' ')),
+		    this.createVertexTemplateEntry(n + 'key', 
+		    		s * 100, s * 47, null, 'Key', null, null, this.getTagsForStencil(gn, '', dt + 'key').join(' ')),
+		    this.createVertexTemplateEntry(n + 'aspect_ratio', 
+		    		s * 100, s * 92, null, 'Aspect Ratio', null, null, this.getTagsForStencil(gn, '', dt + 'aspect ratio').join(' ')),
+		    this.createVertexTemplateEntry(n + 'scale', 
+		    		s * 100, s * 92, null, 'Check', null, null, this.getTagsForStencil(gn, '', dt + 'check scale aspect ratio').join(' ')),
+		    this.createVertexTemplateEntry(n + 'big_query', 
+		    		s * 99, s * 100, null, 'Big Query', null, null, this.getTagsForStencil(gn, '', dt + 'big query').join(' ')),
+		    this.createVertexTemplateEntry(n + 'search', 
+		    		s * 99, s * 100, null, 'Search', null, null, this.getTagsForStencil(gn, '', dt + 'search').join(' ')),
+		    this.createVertexTemplateEntry('html=1;aspect=fixed;strokeColor=none;shadow=0;align=center;verticalAlign=top;fillColor=#2D9C5E;shape=mxgraph.gcp2.search', 
+		    		s * 99, s * 100, null, 'Search (green)', null, null, this.getTagsForStencil(gn, '', dt + 'search').join(' ')),
+		    this.createVertexTemplateEntry(n + 'solution', 
+		    		s * 99, s * 100, null, 'Solution', null, null, this.getTagsForStencil(gn, '', dt + 'solution').join(' ')),
+		    this.createVertexTemplateEntry(n + 'visibility', 
+		    		s * 100, s * 94, null, 'Visibility', null, null, this.getTagsForStencil(gn, '', dt + 'visibility').join(' ')),
+		    this.createVertexTemplateEntry(n + 'anomaly_detection', 
+		    		s * 78, s * 100, null, 'Anomaly Detection', null, null, this.getTagsForStencil(gn, '', dt + 'anomaly detection').join(' ')),
+		    this.createVertexTemplateEntry(n + 'view_list', 
+		    		s * 81, s * 100, null, 'View List', null, null, this.getTagsForStencil(gn, '', dt + 'view list').join(' ')),
+		    this.createVertexTemplateEntry(n + 'connected', 
+		    		s * 100, s * 72, null, 'Admin', null, null, this.getTagsForStencil(gn, '', dt + 'admin system connected').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_server', 
+		    		s * 100, s * 89, null, 'Cloud Server', null, null, this.getTagsForStencil(gn, '', dt + 'cloud server').join(' ')),
+		    this.createVertexTemplateEntry(n + 'primary', 
+		    		s * 100, s * 15, null, 'Primary', null, null, this.getTagsForStencil(gn, '', dt + 'primary').join(' ')),
+		    this.createVertexTemplateEntry(n + 'monitor', 
+		    		s * 100, s * 85, null, 'Monitor', null, null, this.getTagsForStencil(gn, '', dt + 'monitor save help').join(' ')),
+		    this.createVertexTemplateEntry(n + 'monitor_2', 
+		    		s * 100, s * 85, null, 'Monitor', null, null, this.getTagsForStencil(gn, '', dt + 'monitor').join(' ')),
+		    this.createVertexTemplateEntry(n + 'website', 
+		    		s * 100, s * 97, null, 'Website', null, null, this.getTagsForStencil(gn, '', dt + 'website').join(' ')),
+		    this.createVertexTemplateEntry(n + 'safety', 
+		    		s * 100, s * 96, null, 'Safety', null, null, this.getTagsForStencil(gn, '', dt + 'safety').join(' ')),
+		    this.createVertexTemplateEntry(n + 'gear_load', 
+		    		s * 100, s * 92, null, 'Gear Load', null, null, this.getTagsForStencil(gn, '', dt + 'gear load').join(' ')),
+		    this.createVertexTemplateEntry(n + 'files', 
+		    		s * 100, s * 97, null, 'Files', null, null, this.getTagsForStencil(gn, '', dt + 'files data sharing').join(' ')),
+		    this.createVertexTemplateEntry(n + 'play_gear', 
+		    		s * 100, s * 100, null, 'Play Gear', null, null, this.getTagsForStencil(gn, '', dt + 'play gear').join(' ')),
+		    this.createVertexTemplateEntry(n + 'play_start', 
+		    		s * 100, s * 100, null, 'Play Start', null, null, this.getTagsForStencil(gn, '', dt + 'play start').join(' ')),
+		    this.createVertexTemplateEntry(n + 'replication_controller', 
+		    		s * 100, s * 91, null, 'Replication Controller', null, null, this.getTagsForStencil(gn, '', dt + 'replication controller').join(' ')),
+		    this.createVertexTemplateEntry(n + 'replication_controller_2', 
+		    		s * 100, s * 91, null, 'Replication Controller', null, null, this.getTagsForStencil(gn, '', dt + 'replication controller').join(' ')),
+		    this.createVertexTemplateEntry(n + 'replication_controller_3', 
+		    		s * 100, s * 66, null, 'Replication Controller', null, null, this.getTagsForStencil(gn, '', dt + 'replication controller').join(' ')),
+		    this.createVertexTemplateEntry(n + 'repository_2', 
+		    		s * 94, s * 100, null, 'Repository', null, null, this.getTagsForStencil(gn, '', dt + 'repository upload swap').join(' ')),
+		    this.createVertexTemplateEntry(n + 'repository_3', 
+		    		s * 100, s * 100, null, 'Repository', null, null, this.getTagsForStencil(gn, '', dt + 'repository').join(' ')),
+		    this.createVertexTemplateEntry(n + 'repository_primary', 
+		    		s * 100, s * 100, null, 'Repository', null, null, this.getTagsForStencil(gn, '', dt + 'repository primary').join(' ')),
+		    this.createVertexTemplateEntry(n + 'database_3', 
+		    		s * 70, s * 100, null, 'Database', null, null, this.getTagsForStencil(gn, '', dt + 'database db files').join(' ')),
+		    this.createVertexTemplateEntry(n + 'database_uploading', 
+		    		s * 100, s * 84, null, 'Database Uploading', null, null, this.getTagsForStencil(gn, '', dt + 'database db uploading').join(' ')),
+		    this.createVertexTemplateEntry(n + 'servers_stacked', 
+		    		s * 100, s * 100, null, 'Servers Stacked', null, null, this.getTagsForStencil(gn, '', dt + 'servers stacked').join(' ')),
+		    this.createVertexTemplateEntry(n + 'segments', 
+		    		s * 100, s * 100, null, 'Segments', null, null, this.getTagsForStencil(gn, '', dt + 'segments').join(' ')),
+		    this.createVertexTemplateEntry(n + 'segments_2', 
+		    		s * 100, s * 92, null, 'Segments', null, null, this.getTagsForStencil(gn, '', dt + 'segments').join(' ')),
+		    this.createVertexTemplateEntry(n + 'segments_overlap', 
+		    		s * 100, s * 100, null, 'Segments Overlap', null, null, this.getTagsForStencil(gn, '', dt + 'segments overlap').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cost_savings', 
+		    		s * 66, s * 100, null, 'Cost Savings', null, null, this.getTagsForStencil(gn, '', dt + 'cost savings').join(' ')),
+		    this.createVertexTemplateEntry(n + 'enhance_ui', 
+		    		s * 76, s * 100, null, 'Enhance UI', null, null, this.getTagsForStencil(gn, '', dt + 'enhance ui').join(' ')),
+		    this.createVertexTemplateEntry(n + 'phone_android', 
+		    		s * 56, s * 100, null, 'Phone', null, null, this.getTagsForStencil(gn, '', dt + 'phone android').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cost_arrows', 
+		    		s * 76, s * 100, null, 'Cost Arrows', null, null, this.getTagsForStencil(gn, '', dt + 'cost arrows').join(' ')),
+		    this.createVertexTemplateEntry(n + 'increase_cost_arrows', 
+		    		s * 100, s * 92, null, 'Increase Cost Arrows', null, null, this.getTagsForStencil(gn, '', dt + 'increase cost arrows').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cost', 
+		    		s * 85, s * 100, null, 'Cost File', null, null, this.getTagsForStencil(gn, '', dt + 'cost file').join(' ')),
+		    this.createVertexTemplateEntry(n + 'database_2', 
+		    		s * 78, s * 100, null, 'Database', null, null, this.getTagsForStencil(gn, '', dt + 'database db').join(' ')),
+		    this.createVertexTemplateEntry(n + 'database_speed', 
+		    		s * 69, s * 100, null, 'Database Speed', null, null, this.getTagsForStencil(gn, '', dt + 'database db speed').join(' ')),
+		    this.createVertexTemplateEntry(n + 'data_access', 
+		    		s * 93, s * 100, null, 'Data Access', null, null, this.getTagsForStencil(gn, '', dt + 'data access file gear').join(' ')),
+		    this.createVertexTemplateEntry(n + 'database_cycle', 
+		    		s * 100, s * 98, null, 'Database Cycle', null, null, this.getTagsForStencil(gn, '', dt + 'database db cycle').join(' ')),
+		    this.createVertexTemplateEntry(n + 'data_increase', 
+		    		s * 78, s * 100, null, 'Data Increase', null, null, this.getTagsForStencil(gn, '', dt + 'data increase').join(' ')),
+		    this.createVertexTemplateEntry(n + 'data_storage_cost', 
+		    		s * 78, s * 100, null, 'Data Storage Cost', null, null, this.getTagsForStencil(gn, '', dt + 'data storage cost').join(' ')),
+		    this.createVertexTemplateEntry(n + 'gear', 
+		    		s * 100, s * 100, null, 'Gear', null, null, this.getTagsForStencil(gn, '', dt + 'gear').join(' ')),
+		    this.createVertexTemplateEntry(n + 'gear_chain', 
+		    		s * 100, s * 100, null, 'Gear Chain', null, null, this.getTagsForStencil(gn, '', dt + 'gear chain').join(' ')),
+		    this.createVertexTemplateEntry(n + 'bucket_scale', 
+		    		s * 100, s * 81, null, 'Bucket Scale', null, null, this.getTagsForStencil(gn, '', dt + 'bucket scale').join(' ')),
+		    this.createVertexTemplateEntry(n + 'a7_power', 
+		    		s * 100, s * 100, null, 'A7 Power', null, null, this.getTagsForStencil(gn, '', dt + 'a7 power').join(' ')),
+		    this.createVertexTemplateEntry(n + 'gear_arrow', 
+		    		s * 100, s * 61, null, 'Gear Arrow', null, null, this.getTagsForStencil(gn, '', dt + 'gear arrow').join(' ')),
+		    this.createVertexTemplateEntry(n + 'swap', 
+		    		s * 100, s * 51, null, 'Swap', null, null, this.getTagsForStencil(gn, '', dt + 'swap').join(' ')),
+		    this.createVertexTemplateEntry(n + 'save', 
+		    		s * 100, s * 84, null, 'Save', null, null, this.getTagsForStencil(gn, '', dt + 'save').join(' ')),
+		    this.createVertexTemplateEntry(n + 'social_media_time', 
+		    		s * 97, s * 100, null, 'Social Media Time', null, null, this.getTagsForStencil(gn, '', dt + 'social media time').join(' ')),
+		    this.createVertexTemplateEntry(n + 'tape_record', 
+		    		s * 100, s * 71, null, 'Tape Record', null, null, this.getTagsForStencil(gn, '', dt + 'tape record').join(' ')),
+		    this.createVertexTemplateEntry(n + 'folders', 
+		    		s * 100, s * 85, null, 'Folders', null, null, this.getTagsForStencil(gn, '', dt + 'folders extensible').join(' ')),
+		    this.createVertexTemplateEntry(n + 'maps_api', 
+		    		s * 61, s * 100, null, 'Maps API', null, null, this.getTagsForStencil(gn, '', dt + 'maps api application programming interface').join(' ')),
+		    this.createVertexTemplateEntry(n + 'enhance_ui_2', 
+		    		s * 100, s * 91, null, 'Enhance UI', null, null, this.getTagsForStencil(gn, '', dt + 'enhance ui user interface').join(' ')),
+		    this.createVertexTemplateEntry(n + 'certified_industry_standard', 
+		    		s * 100, s * 78, null, 'Certified Industry Standard', null, null, this.getTagsForStencil(gn, '', dt + 'certified industry standard').join(' ')),
+		    this.createVertexTemplateEntry(n + 'calculator', 
+		    		s * 100, s * 74, null, 'Calculator', null, null, this.getTagsForStencil(gn, '', dt + 'calculator').join(' ')),
+		    this.createVertexTemplateEntry(n + 'network', 
+		    		s * 100, s * 100, null, 'Network', null, null, this.getTagsForStencil(gn, '', dt + 'network').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_computer', 
+		    		s * 100, s * 88, null, 'Cloud Computer', null, null, this.getTagsForStencil(gn, '', dt + 'cloud computer').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_connected_insight', 
+		    		s * 100, s * 91, null, 'Cloud Connected Insight', null, null, this.getTagsForStencil(gn, '', dt + 'cloud connected insight').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_information', 
+		    		s * 100, s * 79, null, 'Cloud Information Portable', null, null, this.getTagsForStencil(gn, '', dt + 'cloud information portable').join(' ')),
+		    this.createVertexTemplateEntry(n + 'lifecycle', 
+		    		s * 100, s * 100, null, 'Lifecycle', null, null, this.getTagsForStencil(gn, '', dt + 'lifecycle time folder loading').join(' ')),
+		    this.createVertexTemplateEntry(n + 'thumbs_up', 
+		    		s * 100, s * 100, null, 'Thumbs Up', null, null, this.getTagsForStencil(gn, '', dt + 'thumbs up').join(' ')),
+		    this.createVertexTemplateEntry(n + 'loading_2', 
+		    		s * 93, s * 100, null, 'Loading', null, null, this.getTagsForStencil(gn, '', dt + 'loading').join(' ')),
+		    this.createVertexTemplateEntry(n + 'internet_connection', 
+		    		s * 100, s * 83, null, 'Internet Connection', null, null, this.getTagsForStencil(gn, '', dt + 'internet connection').join(' ')),
+		    this.createVertexTemplateEntry(n + 'check_scale', 
+		    		s * 100, s * 75, null, 'Check Scale', null, null, this.getTagsForStencil(gn, '', dt + 'check scale').join(' ')),
+		    this.createVertexTemplateEntry(n + 'load_balancing', 
+		    		s * 100, s * 26, null, 'Load Balancing', null, null, this.getTagsForStencil(gn, '', dt + 'load balancing').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_messaging', 
+		    		s * 100, s * 64, null, 'Cloud Messaging', null, null, this.getTagsForStencil(gn, '', dt + 'cloud messaging').join(' ')),
+		    this.createVertexTemplateEntry(n + 'memory_card', 
+		    		s * 93, s * 100, null, 'Memory Card', null, null, this.getTagsForStencil(gn, '', dt + 'memory card').join(' ')),
+		    this.createVertexTemplateEntry(n + 'admin_connected', 
+		    		s * 100, s * 100, null, 'Admin Connected', null, null, this.getTagsForStencil(gn, '', dt + 'admin connected').join(' ')),
+		    this.createVertexTemplateEntry('html=1;aspect=fixed;strokeColor=none;shadow=0;align=center;verticalAlign=top;fillColor=#3B8DF1;shape=ellipse', 
+		    		s * 100, s * 100, null, 'Images Service', null, null, this.getTagsForStencil(gn, '', dt + 'images service').join(' ')),
+		    this.createVertexTemplateEntry(n + 'task_queues_2', 
+		    		s * 100, s * 61, null, 'Task Queues', null, null, this.getTagsForStencil(gn, '', dt + 'task queues').join(' ')),
+		    this.createVertexTemplateEntry(n + 'systems_check', 
+		    		s * 99, s * 100, null, 'Systems Check', null, null, this.getTagsForStencil(gn, '', dt + 'systems check').join(' ')),
+		    this.createVertexTemplateEntry(n + 'google_network', 
+		    		s * 100, s * 100, null, 'Google Network', null, null, this.getTagsForStencil(gn, '', dt + 'google network').join(' ')),
+		    this.createVertexTemplateEntry(n + 'check_2', 
+		    		s * 100, s * 100, null, 'Check', null, null, this.getTagsForStencil(gn, '', dt + 'check').join(' ')),
+		    this.createVertexTemplateEntry(n + 'people_security_management', 
+		    		s * 100, s * 100, null, 'People Security Management', null, null, this.getTagsForStencil(gn, '', dt + 'people security management').join(' ')),
+		    this.createVertexTemplateEntry(n + 'search_api', 
+		    		s * 100, s * 100, null, 'Search API', null, null, this.getTagsForStencil(gn, '', dt + 'search api application programming interface').join(' ')),
+		    this.createVertexTemplateEntry(n + 'management_security', 
+		    		s * 100, s * 100, null, 'Management Security', null, null, this.getTagsForStencil(gn, '', dt + 'management security').join(' ')),
+		    this.createVertexTemplateEntry(n + 'loading_3', 
+		    		s * 100, s * 100, null, 'Loading', null, null, this.getTagsForStencil(gn, '', dt + 'loading').join(' ')),
+		    this.createVertexTemplateEntry(n + 'stacked_ownership', 
+		    		s * 100, s * 100, null, 'Stacked Ownership', null, null, this.getTagsForStencil(gn, '', dt + 'stacked ownership').join(' ')),
+		    this.createVertexTemplateEntry(n + 'vpn', 
+		    		s * 100, s * 50, null, 'VPN', null, null, this.getTagsForStencil(gn, '', dt + 'vpn virtual private network').join(' ')),
+		    this.createVertexTemplateEntry(n + 'node', 
+		    		s * 80, s * 100, null, 'Node', null, null, this.getTagsForStencil(gn, '', dt + 'node').join(' ')),
+		    this.createVertexTemplateEntry(n + 'service', 
+		    		s * 70, s * 100, null, 'Service', null, null, this.getTagsForStencil(gn, '', dt + 'service').join(' ')),
+		    this.createVertexTemplateEntry('html=1;aspect=fixed;strokeColor=none;shadow=0;align=center;verticalAlign=top;fillColor=#2D9C5E;shape=mxgraph.gcp2.external_data_center', 
+		    		s * 77, s * 100, null, 'External Data Center', null, null, this.getTagsForStencil(gn, '', dt + 'external data center').join(' ')),
+		    this.createVertexTemplateEntry('html=1;aspect=fixed;strokeColor=none;shadow=0;align=center;verticalAlign=top;fillColor=#2D9C5E;shape=mxgraph.gcp2.external_data_resource', 
+		    		s * 79, s * 100, null, 'External Data Resource', null, null, this.getTagsForStencil(gn, '', dt + 'external data resource').join(' ')),
+		    this.createVertexTemplateEntry('html=1;aspect=fixed;strokeColor=none;shadow=0;align=center;verticalAlign=top;fillColor=#2D9C5E;shape=mxgraph.gcp2.legacy_cloud', 
+		    		s * 100, s * 69, null, 'Legacy Cloud', null, null, this.getTagsForStencil(gn, '', dt + 'legacy cloud').join(' ')),
+		    this.createVertexTemplateEntry('html=1;aspect=fixed;strokeColor=none;shadow=0;align=center;verticalAlign=top;fillColor=#2D9C5E;shape=mxgraph.gcp2.legacy_cloud_2', 
+		    		s * 100, s * 69, null, 'Legacy Cloud', null, null, this.getTagsForStencil(gn, '', dt + 'legacy cloud').join(' ')),
+		    this.createVertexTemplateEntry(n + 'mem_instances', 
+		    		s * 100, s * 87, null, 'Mem Instances', null, null, this.getTagsForStencil(gn, '', dt + 'mem instances').join(' '))
+	 	];
+		
+		this.addPalette('gcp2General Icons', 'GCP / General Icons', false, mxUtils.bind(this, function(content)
+		{
+			for (var i = 0; i < fns.length; i++)
+			{
+				content.appendChild(fns[i](content));
+			}
+		}));
+	};
+	
 	Sidebar.prototype.addGCP2ServiceCardsPalette = function()
 	{
 		var dt = 'gcp google cloud platform service cards ';

+ 1 - 1
src/main/webapp/js/diagramly/sidebar/Sidebar.js

@@ -51,7 +51,7 @@
 	/**
 	 * 
 	 */
-	Sidebar.prototype.gcp2 = ['Paths', 'Zones', 'Service Cards', 'Compute', 'API Platform and Ecosystems', 'Identity and Security', 'Big Data', 'Data Transfer', 'Cloud AI', 'Internet of Things', 'Storage and Databases', 'Management Tools', 'Networking', 'Developer Tools', 'Expanded Product Cards', 'User Device Cards', 'Product Cards'];
+	Sidebar.prototype.gcp2 = ['Paths', 'Zones', 'Service Cards', 'Compute', 'API Platform and Ecosystems', 'Identity and Security', 'Big Data', 'Data Transfer', 'Cloud AI', 'Internet of Things', 'Storage and Databases', 'Management Tools', 'Networking', 'Developer Tools', 'Expanded Product Cards', 'User Device Cards', 'Product Cards', 'General Icons'];
 	
 	/**
 	 *

文件差異過大導致無法顯示
+ 1 - 1
src/main/webapp/js/stencils.min.js


文件差異過大導致無法顯示
+ 12 - 12
src/main/webapp/js/viewer.min.js


文件差異過大導致無法顯示
+ 8635 - 38
src/main/webapp/stencils/gcp2.xml