From 81d5e43ac3ccb393bde9d8e7ca473a04d96403ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bouc=CC=8Cek?= Date: Sun, 12 Dec 2021 00:52:41 +0100 Subject: [PATCH 1/2] WIP --- .clasp.json | 1 + Code.gs => Code.ts | 6 +-- Index.html | 21 ++++------ LICENSE | 2 +- appsscript.json | 18 ++++++++ package-lock.json | 46 +++++++++++++++++++++ package.json | 8 ++++ tsconfig.json | 101 +++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 187 insertions(+), 16 deletions(-) create mode 100644 .clasp.json rename Code.gs => Code.ts (97%) create mode 100644 appsscript.json create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 tsconfig.json diff --git a/.clasp.json b/.clasp.json new file mode 100644 index 0000000..e3a512c --- /dev/null +++ b/.clasp.json @@ -0,0 +1 @@ +{"scriptId":"1glvOtH5vy8_QUR4MEtMwvYpZUfzesJryyhmUIDIkW90yOLK0NOsfTRYy","rootDir":"/Users/bukaj/www/google-script-groups-browser","projectId":"redbitcz-groups-viewer"} diff --git a/Code.gs b/Code.ts similarity index 97% rename from Code.gs rename to Code.ts index f7efc93..2128335 100644 --- a/Code.gs +++ b/Code.ts @@ -1,5 +1,5 @@ -var COMPANY_NAME = "Socialbakers"; -var COMPANY_GSUITE_DOMAIN = "socialbakers.com"; +var COMPANY_NAME = "Redbit"; +var COMPANY_GSUITE_DOMAIN = "redbit.cz"; var TYPE_ALL = "all"; var TYPE_USER = "user"; @@ -22,7 +22,7 @@ var ROLE_TRANSLATE = { var WEB_ARCHIV_URL = "https://groups.google.com/a/" + COMPANY_GSUITE_DOMAIN + "/group/%s"; function doGet() { - return HtmlService.createHtmlOutputFromFile('UI') + return HtmlService.createHtmlOutputFromFile('Index') .setTitle(COMPANY_NAME + ' Google Groups Directory') .addMetaTag('viewport', 'width=device-width, initial-scale=1'); } diff --git a/Index.html b/Index.html index 51a17c6..e74078e 100644 --- a/Index.html +++ b/Index.html @@ -125,8 +125,6 @@ background-color: #fcf8e3; } - - - +
@@ -444,9 +442,8 @@

Google Groups Directory

- \ No newline at end of file + diff --git a/LICENSE b/LICENSE index 278c99e..9251bde 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2016 Jakub Bouček +Copyright (c) 2021 Jakub Bouček Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/appsscript.json b/appsscript.json new file mode 100644 index 0000000..106538f --- /dev/null +++ b/appsscript.json @@ -0,0 +1,18 @@ +{ + "timeZone": "Europe/Prague", + "dependencies": { + "enabledAdvancedServices": [ + { + "userSymbol": "AdminDirectory", + "version": "directory_v1", + "serviceId": "admin" + } + ] + }, + "exceptionLogging": "STACKDRIVER", + "runtimeVersion": "V8", + "webapp": { + "executeAs": "USER_DEPLOYING", + "access": "MYSELF" + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..34a7c3a --- /dev/null +++ b/package-lock.json @@ -0,0 +1,46 @@ +{ + "name": "google-script-groups-browser", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "dependencies": { + "@types/google-apps-script": "^1.0.41" + }, + "devDependencies": { + "typescript": "^4.5.3" + } + }, + "node_modules/@types/google-apps-script": { + "version": "1.0.41", + "resolved": "https://registry.npmjs.org/@types/google-apps-script/-/google-apps-script-1.0.41.tgz", + "integrity": "sha512-Lv8Tila1iNUynITT0H4lR59fcdkZ1JOPQiuthaOoG/agAbWYkZLeaR6yLIeRydFQ2bQqVgOrAXlmu8Ut8uUcOA==" + }, + "node_modules/typescript": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.3.tgz", + "integrity": "sha512-eVYaEHALSt+s9LbvgEv4Ef+Tdq7hBiIZgii12xXJnukryt3pMgJf6aKhoCZ3FWQsu6sydEnkg11fYXLzhLBjeQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + } + }, + "dependencies": { + "@types/google-apps-script": { + "version": "1.0.41", + "resolved": "https://registry.npmjs.org/@types/google-apps-script/-/google-apps-script-1.0.41.tgz", + "integrity": "sha512-Lv8Tila1iNUynITT0H4lR59fcdkZ1JOPQiuthaOoG/agAbWYkZLeaR6yLIeRydFQ2bQqVgOrAXlmu8Ut8uUcOA==" + }, + "typescript": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.3.tgz", + "integrity": "sha512-eVYaEHALSt+s9LbvgEv4Ef+Tdq7hBiIZgii12xXJnukryt3pMgJf6aKhoCZ3FWQsu6sydEnkg11fYXLzhLBjeQ==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..f3bef90 --- /dev/null +++ b/package.json @@ -0,0 +1,8 @@ +{ + "dependencies": { + "@types/google-apps-script": "^1.0.41" + }, + "devDependencies": { + "typescript": "^4.5.3" + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..18653fa --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,101 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Projects */ + // "incremental": true, /* Enable incremental compilation */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "ES2019", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "lib": ["esnext"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ + // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ + "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + + /* Modules */ + "module": "None", /* Specify what module code is generated. */ + "rootDir": "src", /* Specify the root folder within your source files. */ + // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + "resolveJsonModule": true, /* Enable importing .json files */ + "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ + "outDir": "lib", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ + // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} From e8918479aba3fb6f193c958f37e5d46fcd64c7e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bouc=CC=8Cek?= Date: Mon, 13 Dec 2021 19:56:57 +0100 Subject: [PATCH 2/2] WIP --- .gitignore | 1 + Code.ts | 313 +++++++------- Index.html | 895 +++++++++++++++++++++------------------- assets/company-logo.svg | 1 + assets/domain.svg | 17 + assets/favicon.ico | Bin 0 -> 4286 bytes assets/group.svg | 12 + assets/loader.css | 44 ++ assets/user.svg | 12 + tsconfig.json | 2 +- 10 files changed, 718 insertions(+), 579 deletions(-) create mode 100644 .gitignore create mode 100644 assets/company-logo.svg create mode 100644 assets/domain.svg create mode 100644 assets/favicon.ico create mode 100644 assets/group.svg create mode 100644 assets/loader.css create mode 100644 assets/user.svg diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2ccbe46 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/node_modules/ diff --git a/Code.ts b/Code.ts index 2128335..f2696ff 100644 --- a/Code.ts +++ b/Code.ts @@ -1,209 +1,208 @@ -var COMPANY_NAME = "Redbit"; -var COMPANY_GSUITE_DOMAIN = "redbit.cz"; - -var TYPE_ALL = "all"; -var TYPE_USER = "user"; -var TYPE_GROUP = "group"; -var TYPE_DOMAIN = "domain"; -var TYPE_TRANSLATE = { - USER: TYPE_USER, - GROUP: TYPE_GROUP, - CUSTOMER: TYPE_DOMAIN, +import HtmlOutput = GoogleAppsScript.HTML.HtmlOutput; + +const COMPANY_NAME = "Acme"; +const COMPANY_GSUITE_DOMAIN = "acme.com"; + +const TYPE_ALL = "all"; +const TYPE_USER = "user"; +const TYPE_GROUP = "group"; +const TYPE_DOMAIN = "domain"; +const TYPE_TRANSLATE = { + USER: TYPE_USER, + GROUP: TYPE_GROUP, + CUSTOMER: TYPE_DOMAIN, }; -var STATUS_ACTIVE = "ACTIVE"; -var ROLE_OWNER = "owner"; -var ROLE_MANAGER = "manager"; -var ROLE_MEMBER = "member"; -var ROLE_TRANSLATE = { - OWNER: ROLE_OWNER, - MANAGER: ROLE_MANAGER, - MEMBER: ROLE_MEMBER, +const STATUS_ACTIVE = "ACTIVE"; +const ROLE_OWNER = "owner"; +const ROLE_MANAGER = "manager"; +const ROLE_MEMBER = "member"; +const ROLE_TRANSLATE = { + OWNER: ROLE_OWNER, + MANAGER: ROLE_MANAGER, + MEMBER: ROLE_MEMBER, }; -var WEB_ARCHIV_URL = "https://groups.google.com/a/" + COMPANY_GSUITE_DOMAIN + "/group/%s"; +const WEB_ARCHIV_URL = "https://groups.google.com/a/" + COMPANY_GSUITE_DOMAIN + "/group/%s"; -function doGet() { - return HtmlService.createHtmlOutputFromFile('Index') - .setTitle(COMPANY_NAME + ' Google Groups Directory') - .addMetaTag('viewport', 'width=device-width, initial-scale=1'); +function doGet(): HtmlOutput { + return HtmlService.createHtmlOutputFromFile('Index') + .setTitle(COMPANY_NAME + ' Google Groups Directory') + .setFaviconUrl('https://jakubboucek.github.io/google-script-groups-browser/assets/favicon.ico') + .addMetaTag('viewport', 'width=device-width, initial-scale=1'); } function search(id, type) { - if(type==TYPE_ALL) { - return getAllGroupsResponse(id, type); - } + if (type == TYPE_ALL) { + return getAllGroupsResponse(id, type); + } - var email = completeEmail(id); - var entity = searchEntity(email, type); + var email = completeEmail(id); + var entity = searchEntity(email, type); - if(!entity) { - return getErrorResponse("Email address '" + email + "' doesn't exist on the domain."); - } + if (!entity) { + return getErrorResponse("Email address '" + email + "' doesn't exist on the domain."); + } - if(entity.type == TYPE_GROUP) { - return getGroupMembersResponse(email, entity.object); - } + if (entity.type == TYPE_GROUP) { + return getGroupMembersResponse(email, entity.object); + } - if(entity.type == TYPE_USER) { - return getUserGroupsResponse(email, entity.object); - } + if (entity.type == TYPE_USER) { + return getUserGroupsResponse(email, entity.object); + } } function getAllGroupsResponse(id, type) { - var groups = fetchGroups({customer:'my_customer'}); - return { - status: true, - type: TYPE_ALL, - groups: groups, - }; + var groups = fetchGroups({customer: 'my_customer'}); + return { + status: true, + type: TYPE_ALL, + groups: groups, + }; } function getUserGroupsResponse(id, user) { - var groups = fetchGroups({userKey:id}); - return { - status: true, - type: TYPE_USER, - groups: groups, - user: user, - }; + var groups = fetchGroups({userKey: id}); + return { + status: true, + type: TYPE_USER, + groups: groups, + user: user, + }; } function fetchGroups(filter) { - var groups = []; - var pageToken = null; - do { - var result = AdminDirectory.Groups.list(filter); - filter.pageToken = result.nextPageToken; - if(result.groups) { - groups = groups.concat(result.groups.map(function(group) { - return { - email: group.email, - name: group.name, - description: group.description, - aliases: group.aliases, - }; - })); + var groups = []; + var pageToken = null; + do { + var result = AdminDirectory.Groups.list(filter); + filter.pageToken = result.nextPageToken; + if (result.groups) { + groups = groups.concat(result.groups.map(function (group) { + return { + email: group.email, + name: group.name, + description: group.description, + aliases: group.aliases, + }; + })); + } } - } - while(result.nextPageToken); + while (result.nextPageToken); - return groups; + return groups; } function getGroupMembersResponse(id, group) { - var members = fetchMembers(id); - return { - status: true, - type: TYPE_GROUP, - members: members, - group: group, - }; + var members = fetchMembers(id); + return { + status: true, + type: TYPE_GROUP, + members: members, + group: group, + }; } function fetchMembers(email) { - var userEmail = Session.getActiveUser().getEmail(); - var members = { - owner: [], - manager: [], - member: [], - }; - var pageToken = null; - do { - var result = AdminDirectory.Members.list(email, {pageToken:pageToken}); - pageToken = result.nextPageToken; - result.members.forEach(function(member){ - var role = ROLE_TRANSLATE[member.role]; - var type = TYPE_TRANSLATE[member.type]; - var email= member.email ? member.email : null; - - members[role].push({ - email: email, - type: type, - role: role, - status: member.status == STATUS_ACTIVE, - me: email == userEmail, - }); - }); - } - while(result.nextPageToken); - return members; + var userEmail = Session.getActiveUser().getEmail(); + var members = { + owner: [], + manager: [], + member: [], + }; + var pageToken = null; + do { + var result = AdminDirectory.Members.list(email, {pageToken: pageToken}); + pageToken = result.nextPageToken; + result.members.forEach(function (member) { + var role = ROLE_TRANSLATE[member.role]; + var type = TYPE_TRANSLATE[member.type]; + var email = member.email ? member.email : null; + + members[role].push({ + email: email, + type: type, + role: role, + status: member.status == STATUS_ACTIVE, + me: email == userEmail, + }); + }); + } + while (result.nextPageToken); + return members; } function getErrorResponse(error) { - return { - status: false, - type: null, - error: error, - } + return { + status: false, + type: null, + error: error, + } } function getGroupInfo(groupKey) { - var group = AdminDirectory.Groups.get(groupKey); - return { - name: group.name, - email: group.email, - description: group.description, - aliases: group.aliases, - webUrl: WEB_ARCHIV_URL.replace('%s', cropUsername(group.email)), - }; + var group = AdminDirectory.Groups.get(groupKey); + return { + name: group.name, + email: group.email, + description: group.description, + aliases: group.aliases, + webUrl: WEB_ARCHIV_URL.replace('%s', cropUsername(group.email)), + }; } function getUserInfo(userKey) { - var user = AdminDirectory.Users.get(userKey); - return { - name: user.name, - email: user.primaryEmail, - photo: user.thumbnailPhotoUrl, - aliases: user.aliases, - active: ! user.suspended, - }; + var user = AdminDirectory.Users.get(userKey); + return { + name: user.name, + email: user.primaryEmail, + photo: user.thumbnailPhotoUrl, + aliases: user.aliases, + active: !user.suspended, + }; } function completeEmail(shortEmail) { - if (shortEmail.indexOf('@') == -1) { - var currentUser = Session.getEffectiveUser().getEmail(); - var domain = currentUser.substring(currentUser.indexOf('@')); - return shortEmail + domain; - } - return shortEmail; + if (shortEmail.indexOf('@') == -1) { + var currentUser = Session.getEffectiveUser().getEmail(); + var domain = currentUser.substring(currentUser.indexOf('@')); + return shortEmail + domain; + } + return shortEmail; } function cropUsername(email) { - return email.substring(0, email.indexOf('@')); + return email.substring(0, email.indexOf('@')); } function searchEntity(id, type) { - try { - var entity = { - type: type, - object: null, - }; + try { + var entity = { + type: type, + object: null, + }; - if(type==TYPE_GROUP) { - entity.object = getGroupInfo(id); - } - else if(type==TYPE_USER) { - entity.object = getUserInfo(id); - } - else { - try { - entity.object = getGroupInfo(id); - entity.type=TYPE_GROUP; - } - catch(error){ - entity.object = getUserInfo(id); - entity.type=TYPE_USER; - } + if (type == TYPE_GROUP) { + entity.object = getGroupInfo(id); + } else if (type == TYPE_USER) { + entity.object = getUserInfo(id); + } else { + try { + entity.object = getGroupInfo(id); + entity.type = TYPE_GROUP; + } catch (error) { + entity.object = getUserInfo(id); + entity.type = TYPE_USER; + } + } + return entity; + } catch (error) { + Logger.log(error); + return false; } - return entity; - } - catch(error){ - Logger.log(error); - return false; - } } -function getUrl(){ - return ScriptApp.getService().getUrl(); +function getUrl() { + return ScriptApp.getService().getUrl(); } diff --git a/Index.html b/Index.html index e74078e..d86d320 100644 --- a/Index.html +++ b/Index.html @@ -1,449 +1,502 @@ - + - + - - - - + + + + - - - -
-
+ + + +
+
-

Google Groups Directory

-

Email address (user or group):

-
-
-
-
- -
-
+

Google Groups Directory

+

Email address (user or group):

+
+
+ +
+
+ +
+
+ +
+
+
-
+
-

About User

-
-
-
- - - - - - - - - - -
Name:
E-mail:
Aliases:
+

About User

+
+
+
+ + + + + + + + + + + + + +
Name:
E-mail:
Aliases:
+
-
-

About Group

-
-
- -

Go to the Group
only for members

+

About Group

+
+
+ +

Go to the Group
only for + members

+
+
+ + + + + + + + + + + + + + + + + +
Name:
Description:
E-mail:
Aliases:
+
-
- - - - - - - - - - - - - -
Name:
Description:
E-mail:
Aliases:
-
-
-

Groups

- - - - - -
+

Groups

+ + + + + +
-

Group members

- - - - - - -
+

Group members

+ + + + + + +
-
-
- - +
+ + diff --git a/assets/company-logo.svg b/assets/company-logo.svg new file mode 100644 index 0000000..4d027af --- /dev/null +++ b/assets/company-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/domain.svg b/assets/domain.svg new file mode 100644 index 0000000..235ef07 --- /dev/null +++ b/assets/domain.svg @@ -0,0 +1,17 @@ + + + + Crop + Created with Sketch. + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/favicon.ico b/assets/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..6b8f9c30c701dd9cecb5349c8b9a3f3c3923622a GIT binary patch literal 4286 zcmeI0ziU%b7>3Vnr3EQkIyi|Gaqv%Y5^?ZP5OHvD5{Do`L_|t18QdI2q*QQ_Qc4k# z4&so2IEaWiIEY{?B2q-Eh*%89=WX(Z&%?bp(b%LzZ+Losz2Enqb8>TX(-0C~)6+qJ z!~A3j`$7nZfv#{2)W4msCR2ke!!&`IMQh)LvgjYGt`iJ!S&rH$%KjY6v;%>nM-&a&edk^NkhPKZC zUj2Wdy$DmvL3tkZy`{&B!VAqI_zEQnDW{+e-=SB3(=~|s44RMn-ouH!2{3jX-hs4= zSqJ5?e7-E&f75*;_Ab1La=fH{9WJy{{W(~iN@*0k7WJE^o4@9MpuLA9)bHoyv3$N< zMmy4u-A`S6=*Ly>=D+Os8U2}z9C1!-pN(R(=HAU;@AZV`p?)*+e@y!{oPt_3HtXVc zGiLXM&99gBOQZMn65IhF`;_*W^VmiENu*Is8J+U9sxp5Fi?ltBOh literal 0 HcmV?d00001 diff --git a/assets/group.svg b/assets/group.svg new file mode 100644 index 0000000..4b7eaa9 --- /dev/null +++ b/assets/group.svg @@ -0,0 +1,12 @@ + + + + Crop + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/assets/loader.css b/assets/loader.css new file mode 100644 index 0000000..194d17d --- /dev/null +++ b/assets/loader.css @@ -0,0 +1,44 @@ +.loader { + margin: 15px auto; + font-size: 3px; + position: relative; + text-indent: -9999em; + border-top: 1.1em solid rgba(89, 89, 89, 0.2); + border-right: 1.1em solid rgba(89, 89, 89, 0.2); + border-bottom: 1.1em solid rgba(89, 89, 89, 0.2); + border-left: 1.1em solid #595959; + -webkit-transform: translateZ(0); + -ms-transform: translateZ(0); + transform: translateZ(0); + -webkit-animation: load8 1.1s infinite linear; + animation: load8 1.1s infinite linear; +} + +.loader, +.loader:after { + border-radius: 50%; + width: 10em; + height: 10em; +} + +@-webkit-keyframes load8 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +@keyframes load8 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} diff --git a/assets/user.svg b/assets/user.svg new file mode 100644 index 0000000..3c30446 --- /dev/null +++ b/assets/user.svg @@ -0,0 +1,12 @@ + + + + Crop + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 18653fa..21268b7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -67,7 +67,7 @@ // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ /* Interop Constraints */ - "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + "isolatedModules": false, /* Ensure that each file can be safely transpiled without relying on other imports. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */