diff --git a/Readme.md b/Readme.md index f8724413ffc..60c423856b4 100644 --- a/Readme.md +++ b/Readme.md @@ -201,3 +201,7 @@ let mut a = String::from("a"); ```` + +### Adding to Valid Tag List + +Markdown parsers don't handle `` very well. If you intended to write what the parser interprets as usage of an element / web component, navigate to `capi/src/init-node/valid-tags.json` and add a new entry for your tag. If you meant for `` to be text, you'll need to escape it with a backslash (`\`). Please confirm that this renders properly before PRing with your changes. diff --git a/capi/src/init-node/html-to-hyperscript.ts b/capi/src/init-node/html-to-hyperscript.ts index 58360e3212c..dd80dede300 100644 --- a/capi/src/init-node/html-to-hyperscript.ts +++ b/capi/src/init-node/html-to-hyperscript.ts @@ -1,7 +1,9 @@ -// eslint-disable-next-line +import * as path from "path"; // @ts-ignore import * as parse5 from "parse5"; import * as t from "../types"; +import validTags from "./valid-tags.json"; +import {Ctx} from "../types/ctx"; interface HTMLAttr { name: string; @@ -33,6 +35,7 @@ const Attrs = (attrs: HTMLAttr[]): Record | null => { }; const Hyperscript = ( + ctx: Ctx, node: HTMLNode, attributes: t.Page, srcPath: string, @@ -40,15 +43,43 @@ const Hyperscript = ( if (node.nodeName === "#text") { return node.value as string; } + + if (node.nodeName === "#comment") { + return null; + } + + if (node.tagName) { + if (!validTags[node.tagName] && !node.tagName.startsWith("amplify-")) { + throw new Error( + `Invalid tag "${ + node.tagName + }" encountered in "${srcPath}". See instructions on adding valid tags at "${path.resolve( + ctx.config.cwd as string, + "Readme.md#adding-to-valid-tag-list", + )}"`, + ); + } + } else { + throw new Error( + `Undefined is not a valid tag name, encountered in "${srcPath}". No info:\n${node}`, + ); + } + const props = node.attrs ? Attrs(node.attrs) : null; if (props?.style) { throw new Error(`'style' attribute used in "${srcPath}"`); } + const children = node.childNodes && node.childNodes.length > 0 ? // eslint-disable-next-line node.childNodes.reduce((acc: any, childNode: any) => { - const hyperscriptNode = Hyperscript(childNode, attributes, srcPath); + const hyperscriptNode = Hyperscript( + ctx, + childNode, + attributes, + srcPath, + ); switch (hyperscriptNode) { case undefined: case null: @@ -59,6 +90,7 @@ const Hyperscript = ( } }, new Array()) : new Array(); + const hyperscriptNode = [ node.tagName, props, @@ -90,6 +122,7 @@ const Hyperscript = ( * Turns an HTML source string into an array of Hyperscript nodes */ export const htmlToHyperscript = ( + ctx: Ctx, html: string, srcPath: string, attributes: t.Page, @@ -99,6 +132,6 @@ export const htmlToHyperscript = ( return parse5 .parseFragment(html, {scriptingEnabled: true}) .childNodes?.map((node: HTMLNode) => - Hyperscript(node, attributes, srcPath), + Hyperscript(ctx, node, attributes, srcPath), ); }; diff --git a/capi/src/init-node/index.ts b/capi/src/init-node/index.ts index 4524e1cf5f3..20ff42daf76 100644 --- a/capi/src/init-node/index.ts +++ b/capi/src/init-node/index.ts @@ -87,7 +87,7 @@ export async function initNode(srcPath: string, ctx: t.Ctx): Promise { const contents = (await fs.readFile(srcPath)).toString(); const {body: markdownBody, attributes} = fm(contents); const htmlBody = marked(markdownBody); - const body = htmlToHyperscript(htmlBody, srcPath, attributes); + const body = htmlToHyperscript(ctx, htmlBody, srcPath, attributes); // @ts-ignore if (attributes.disableLinkification) { // @ts-ignore @@ -111,7 +111,9 @@ export async function initNode(srcPath: string, ctx: t.Ctx): Promise { ); } ctx.pageBySrcPath.set(srcPath, { + // @ts-ignore route: pathDeduction.route, + // @ts-ignore body, ...attributes, }); diff --git a/capi/src/init-node/valid-tags.json b/capi/src/init-node/valid-tags.json new file mode 100644 index 00000000000..6aff453f25e --- /dev/null +++ b/capi/src/init-node/valid-tags.json @@ -0,0 +1,56 @@ +{ + "a": true, + "amplify-block": true, + "amplify-block-switcher": true, + "amplify-callout": true, + "amplify-code-block": true, + "amplify-confirm-sign-in": true, + "amplify-confirm-sign-up": true, + "amplify-container": true, + "amplify-forgot-password": true, + "amplify-greetings": true, + "amplify-require-new-password": true, + "amplify-responsive-grid": true, + "amplify-sign-in": true, + "amplify-sign-out": true, + "amplify-sign-up": true, + "b": true, + "blockquote": true, + "br": true, + "code": true, + "div": true, + "docs-card": true, + "docs-component-playground": true, + "docs-container": true, + "docs-filter": true, + "docs-footer": true, + "docs-hero": true, + "docs-internal-link-button": true, + "docs-landing-hero-cta": true, + "docs-link-banner": true, + "em": true, + "h1": true, + "h2": true, + "h3": true, + "h4": true, + "h5": true, + "hr": true, + "iframe": true, + "img": true, + "inline-fragment": true, + "li": true, + "ol": true, + "p": true, + "pre": true, + "span": true, + "strong": true, + "table": true, + "tbody": true, + "td": true, + "tds": true, + "th": true, + "thead": true, + "tr": true, + "ui-component-props": true, + "ul": true +} diff --git a/capi/src/types/config.ts b/capi/src/types/config.ts index befed5d103a..6ae10753548 100644 --- a/capi/src/types/config.ts +++ b/capi/src/types/config.ts @@ -4,8 +4,8 @@ export interface Config { exclude?: string[]; filters: Readonly, Readonly[]>>>; hooks?: { - onTargetsWritten?: () => {}; - onWatching?: () => {}; + onTargetsWritten?: () => void; + onWatching?: () => void; }; outDir: string; publicDir: string; diff --git a/capi/tsconfig.json b/capi/tsconfig.json index 45bf0d9981b..4c311b832ac 100644 --- a/capi/tsconfig.json +++ b/capi/tsconfig.json @@ -1,9 +1,10 @@ { "compilerOptions": { + "downlevelIteration": true, "lib": ["dom", "es2018", "es2018.AsyncIterable"], "outDir": "lib", - "typeRoots": ["node_modules/@types", "../node_modules/@types"], - "downlevelIteration": true + "resolveJsonModule": true, + "typeRoots": ["node_modules/@types", "../node_modules/@types"] }, "extends": "../tsconfig.base.json", "include": ["src"] diff --git a/client/prerender-config.js b/client/prerender-config.js deleted file mode 100644 index 27d4cfa951a..00000000000 --- a/client/prerender-config.js +++ /dev/null @@ -1,22 +0,0 @@ -// eslint-disable-next-line -const path = require("path"); -const project = path.join(__dirname, "../tsconfig.json"); -require("ts-node").register({project}); -// eslint-disable-next-line -const {routes: entryUrls} = require("./www/api/routes"); - -module.exports = { - entryUrls, - hydrateOptions() { - return { - addModulePreloads: true, - removeUnusedStyles: true, - minifyStyleElements: true, - minifyScriptElements: true, - removeAttributeQuotes: true, - removeBooleanAttributeQuotes: true, - removeEmptyAttributes: true, - removeHtmlComments: true, - }; - }, -}; diff --git a/client/prerender.config.ts b/client/prerender.config.ts new file mode 100644 index 00000000000..1f603d4e18e --- /dev/null +++ b/client/prerender.config.ts @@ -0,0 +1,25 @@ +import {PrerenderConfig} from "@stencil/core"; +import {routes as entryUrls} from "./src/api/routes"; + +export const config: PrerenderConfig = { + crawlUrls: false, + entryUrls, + hydrateOptions() { + return { + addModulePreloads: true, + removeUnusedStyles: true, + minifyStyleElements: true, + minifyScriptElements: true, + removeAttributeQuotes: true, + removeBooleanAttributeQuotes: true, + removeEmptyAttributes: true, + removeHtmlComments: true, + maxHydrateCount: 2000, + runtimeLogging: true, + timeout: 1000000, + }; + }, + filterUrl(url) { + return !!(url && entryUrls.includes(url.pathname) && url.pathname !== "/"); + }, +}; diff --git a/client/src/amplify-ui/sidebar-layout/sidebar-layout-main/__snapshots__/sidebar-layout-main.spec.ts.snap b/client/src/amplify-ui/sidebar-layout/sidebar-layout-main/__snapshots__/sidebar-layout-main.spec.ts.snap index 79930a7cb51..dfff586dd6e 100644 --- a/client/src/amplify-ui/sidebar-layout/sidebar-layout-main/__snapshots__/sidebar-layout-main.spec.ts.snap +++ b/client/src/amplify-ui/sidebar-layout/sidebar-layout-main/__snapshots__/sidebar-layout-main.spec.ts.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`amplify-sidebar-layout-main Render logic should render 1`] = ` - +
diff --git a/client/src/amplify-ui/sidebar-layout/sidebar-layout-main/sidebar-layout-main.style.ts b/client/src/amplify-ui/sidebar-layout/sidebar-layout-main/sidebar-layout-main.style.ts index 3412d8262b0..075b7237baa 100644 --- a/client/src/amplify-ui/sidebar-layout/sidebar-layout-main/sidebar-layout-main.style.ts +++ b/client/src/amplify-ui/sidebar-layout/sidebar-layout-main/sidebar-layout-main.style.ts @@ -23,7 +23,7 @@ export const sidebarLayoutMainStyle = css` ${MQFablet} { min-width: initial; - padding: 0 3rem; + padding: 0 2.5rem; } } `; diff --git a/client/src/components.d.ts b/client/src/components.d.ts index 3abf0072407..c22b0482819 100644 --- a/client/src/components.d.ts +++ b/client/src/components.d.ts @@ -62,8 +62,6 @@ export namespace Components { */ "redirect"?: boolean; } - interface AmplifyHero { - } interface AmplifyLorem { } interface AmplifyResponsiveGrid { @@ -206,6 +204,8 @@ export namespace Components { } interface DocsFourOFour { } + interface DocsHero { + } interface DocsInPageLink { /** * * the selected filter state @@ -304,6 +304,8 @@ export namespace Components { } interface DocsRouter { } + interface DocsSearchBar { + } interface DocsSecondaryNav { /** * * the current filter state @@ -398,12 +400,6 @@ declare global { prototype: HTMLAmplifyExternalLinkElement; new (): HTMLAmplifyExternalLinkElement; }; - interface HTMLAmplifyHeroElement extends Components.AmplifyHero, HTMLStencilElement { - } - var HTMLAmplifyHeroElement: { - prototype: HTMLAmplifyHeroElement; - new (): HTMLAmplifyHeroElement; - }; interface HTMLAmplifyLoremElement extends Components.AmplifyLorem, HTMLStencilElement { } var HTMLAmplifyLoremElement: { @@ -518,6 +514,12 @@ declare global { prototype: HTMLDocsFourOFourElement; new (): HTMLDocsFourOFourElement; }; + interface HTMLDocsHeroElement extends Components.DocsHero, HTMLStencilElement { + } + var HTMLDocsHeroElement: { + prototype: HTMLDocsHeroElement; + new (): HTMLDocsHeroElement; + }; interface HTMLDocsInPageLinkElement extends Components.DocsInPageLink, HTMLStencilElement { } var HTMLDocsInPageLinkElement: { @@ -584,6 +586,12 @@ declare global { prototype: HTMLDocsRouterElement; new (): HTMLDocsRouterElement; }; + interface HTMLDocsSearchBarElement extends Components.DocsSearchBar, HTMLStencilElement { + } + var HTMLDocsSearchBarElement: { + prototype: HTMLDocsSearchBarElement; + new (): HTMLDocsSearchBarElement; + }; interface HTMLDocsSecondaryNavElement extends Components.DocsSecondaryNav, HTMLStencilElement { } var HTMLDocsSecondaryNavElement: { @@ -620,7 +628,6 @@ declare global { "amplify-callout": HTMLAmplifyCalloutElement; "amplify-code-block": HTMLAmplifyCodeBlockElement; "amplify-external-link": HTMLAmplifyExternalLinkElement; - "amplify-hero": HTMLAmplifyHeroElement; "amplify-lorem": HTMLAmplifyLoremElement; "amplify-responsive-grid": HTMLAmplifyResponsiveGridElement; "amplify-sidebar-layout": HTMLAmplifySidebarLayoutElement; @@ -640,6 +647,7 @@ declare global { "docs-feedback-callout": HTMLDocsFeedbackCalloutElement; "docs-footer": HTMLDocsFooterElement; "docs-four-o-four": HTMLDocsFourOFourElement; + "docs-hero": HTMLDocsHeroElement; "docs-in-page-link": HTMLDocsInPageLinkElement; "docs-internal-link": HTMLDocsInternalLinkElement; "docs-internal-link-button": HTMLDocsInternalLinkButtonElement; @@ -651,6 +659,7 @@ declare global { "docs-page": HTMLDocsPageElement; "docs-repo-actions": HTMLDocsRepoActionsElement; "docs-router": HTMLDocsRouterElement; + "docs-search-bar": HTMLDocsSearchBarElement; "docs-secondary-nav": HTMLDocsSecondaryNavElement; "docs-select-anchor": HTMLDocsSelectAnchorElement; "docs-universal-nav": HTMLDocsUniversalNavElement; @@ -709,8 +718,6 @@ declare namespace LocalJSX { */ "redirect"?: boolean; } - interface AmplifyHero { - } interface AmplifyLorem { } interface AmplifyResponsiveGrid { @@ -853,6 +860,8 @@ declare namespace LocalJSX { } interface DocsFourOFour { } + interface DocsHero { + } interface DocsInPageLink { /** * * the selected filter state @@ -951,6 +960,8 @@ declare namespace LocalJSX { } interface DocsRouter { } + interface DocsSearchBar { + } interface DocsSecondaryNav { /** * * the current filter state @@ -1019,7 +1030,6 @@ declare namespace LocalJSX { "amplify-callout": AmplifyCallout; "amplify-code-block": AmplifyCodeBlock; "amplify-external-link": AmplifyExternalLink; - "amplify-hero": AmplifyHero; "amplify-lorem": AmplifyLorem; "amplify-responsive-grid": AmplifyResponsiveGrid; "amplify-sidebar-layout": AmplifySidebarLayout; @@ -1039,6 +1049,7 @@ declare namespace LocalJSX { "docs-feedback-callout": DocsFeedbackCallout; "docs-footer": DocsFooter; "docs-four-o-four": DocsFourOFour; + "docs-hero": DocsHero; "docs-in-page-link": DocsInPageLink; "docs-internal-link": DocsInternalLink; "docs-internal-link-button": DocsInternalLinkButton; @@ -1050,6 +1061,7 @@ declare namespace LocalJSX { "docs-page": DocsPage; "docs-repo-actions": DocsRepoActions; "docs-router": DocsRouter; + "docs-search-bar": DocsSearchBar; "docs-secondary-nav": DocsSecondaryNav; "docs-select-anchor": DocsSelectAnchor; "docs-universal-nav": DocsUniversalNav; @@ -1066,7 +1078,6 @@ declare module "@stencil/core" { "amplify-callout": LocalJSX.AmplifyCallout & JSXBase.HTMLAttributes; "amplify-code-block": LocalJSX.AmplifyCodeBlock & JSXBase.HTMLAttributes; "amplify-external-link": LocalJSX.AmplifyExternalLink & JSXBase.HTMLAttributes; - "amplify-hero": LocalJSX.AmplifyHero & JSXBase.HTMLAttributes; "amplify-lorem": LocalJSX.AmplifyLorem & JSXBase.HTMLAttributes; "amplify-responsive-grid": LocalJSX.AmplifyResponsiveGrid & JSXBase.HTMLAttributes; "amplify-sidebar-layout": LocalJSX.AmplifySidebarLayout & JSXBase.HTMLAttributes; @@ -1086,6 +1097,7 @@ declare module "@stencil/core" { "docs-feedback-callout": LocalJSX.DocsFeedbackCallout & JSXBase.HTMLAttributes; "docs-footer": LocalJSX.DocsFooter & JSXBase.HTMLAttributes; "docs-four-o-four": LocalJSX.DocsFourOFour & JSXBase.HTMLAttributes; + "docs-hero": LocalJSX.DocsHero & JSXBase.HTMLAttributes; "docs-in-page-link": LocalJSX.DocsInPageLink & JSXBase.HTMLAttributes; "docs-internal-link": LocalJSX.DocsInternalLink & JSXBase.HTMLAttributes; "docs-internal-link-button": LocalJSX.DocsInternalLinkButton & JSXBase.HTMLAttributes; @@ -1097,6 +1109,7 @@ declare module "@stencil/core" { "docs-page": LocalJSX.DocsPage & JSXBase.HTMLAttributes; "docs-repo-actions": LocalJSX.DocsRepoActions & JSXBase.HTMLAttributes; "docs-router": LocalJSX.DocsRouter & JSXBase.HTMLAttributes; + "docs-search-bar": LocalJSX.DocsSearchBar & JSXBase.HTMLAttributes; "docs-secondary-nav": LocalJSX.DocsSecondaryNav & JSXBase.HTMLAttributes; "docs-select-anchor": LocalJSX.DocsSelectAnchor & JSXBase.HTMLAttributes; "docs-universal-nav": LocalJSX.DocsUniversalNav & JSXBase.HTMLAttributes; diff --git a/client/src/constants/algolia.ts b/client/src/constants/algolia.ts new file mode 100644 index 00000000000..ab4d671f8b4 --- /dev/null +++ b/client/src/constants/algolia.ts @@ -0,0 +1,4 @@ +export const ALGOLIA_API_KEY = "24d37f059982b2f5ecf829afe93aed40"; +export const ALGOLIA_INDEX_NAME = "aws_amplify_new"; +export const UNINITIALIZED_SEARCH_INPUT_SELECTOR = + "#amplify-docs-search-input:not(.ds-input)"; diff --git a/client/src/constants/img.ts b/client/src/constants/img.ts new file mode 100644 index 00000000000..cddf0ad3b89 --- /dev/null +++ b/client/src/constants/img.ts @@ -0,0 +1,90 @@ +export const EXTERNAL_LINK = { + alt: "External Link", + white: "/assets/external-link-white.svg", + black: "/assets/external-link-black.svg", +}; + +export const DISCORD = { + alt: "Discord Logo", + lightSrc: "/assets/discord-white.svg", + darkSrc: "/assets/discord-black.svg", + blueSrc: "/assets/discord-blue.svg", +}; + +export const CLOSE = { + alt: "Close", + src: "/assets/close.svg", +}; + +export const AMPLIFY = { + alt: "Amplify Logo", + lightSrc: "/assets/logo-light.svg", + darkSrc: "/assets/logo-dark.svg", +}; + +export const TWITTER = { + alt: "Twitter Logo", + src: "/assets/twitter.svg", +}; + +export const GITHUB = { + alt: "GitHub Logo", + lightSrc: "/assets/github-light.svg", + darkSrc: "/assets/github.svg", +}; + +export const AWS = { + alt: "AWS Logo", + lightSrc: "/assets/aws.svg", + darkSrc: "/assets/aws-dark.svg", +}; + +export const JS = { + src: "/assets/integrations/js.svg", + alt: "JS Icon", +}; + +export const IOS = { + src: "/assets/integrations/ios.svg", + alt: "iOS Icon", +}; + +export const ANDROID = { + src: "/assets/integrations/android.svg", + alt: "Android Icon", +}; + +export const NEXT_PAGE = { + src: "/assets/arrow-left.svg", + alt: "Previous Page", +}; + +export const PREVIOUS_PAGE = { + src: "/assets/arrow-right.svg", + alt: "Next Page", +}; + +export const BURGER = { + src: "/assets/burger.svg", + alt: "Open Menu", +}; + +export const EX = { + src: "/assets/close.svg", + alt: "Close Menu", +}; + +export const FLAG = { + src: "/assets/flag.svg", + alt: "Feedback", +}; + +export const EDIT = { + src: "/assets/github.svg", + alt: "Edit", +}; + +export const SEARCH = { + src: "/assets/search.svg", + alt: "Search", +}; diff --git a/client/src/docs-ui/chat-button/__snapshots__/chat-button.spec.ts.snap b/client/src/docs-ui/chat-button/__snapshots__/chat-button.spec.ts.snap index d8770ae0107..a21d576f0ec 100644 --- a/client/src/docs-ui/chat-button/__snapshots__/chat-button.spec.ts.snap +++ b/client/src/docs-ui/chat-button/__snapshots__/chat-button.spec.ts.snap @@ -3,7 +3,7 @@ exports[`docs-chat-button Render logic should render 1`] = ` - + Discord Logo Open Chat diff --git a/client/src/docs-ui/chat-button/chat-button.tsx b/client/src/docs-ui/chat-button/chat-button.tsx index da4626b1553..040d2e898e7 100644 --- a/client/src/docs-ui/chat-button/chat-button.tsx +++ b/client/src/docs-ui/chat-button/chat-button.tsx @@ -1,17 +1,22 @@ import {Component, h} from "@stencil/core"; import {discordChatStyle, logoStyle} from "./chat-button.style"; -import {DISCORD} from "../../constants/links"; +import {DISCORD as DISCORD_LINK} from "../../constants/links"; +import {DISCORD as DISCORD_IMG} from "../../constants/img"; @Component({tag: "docs-chat-button", shadow: false}) export class DocsChatButton { render() { return ( - + {DISCORD_IMG.alt} Open Chat ); diff --git a/client/src/docs-ui/footer/__snapshots__/footer.spec.ts.snap b/client/src/docs-ui/footer/__snapshots__/footer.spec.ts.snap index 8c6bd913548..3b6c1f3e859 100644 --- a/client/src/docs-ui/footer/__snapshots__/footer.spec.ts.snap +++ b/client/src/docs-ui/footer/__snapshots__/footer.spec.ts.snap @@ -41,7 +41,7 @@ exports[`docs-footer Render logic should render 1`] = ` - + Discord Logo diff --git a/client/src/docs-ui/footer/footer.tsx b/client/src/docs-ui/footer/footer.tsx index 273c9e3f438..8eafbf72ab5 100644 --- a/client/src/docs-ui/footer/footer.tsx +++ b/client/src/docs-ui/footer/footer.tsx @@ -8,6 +8,7 @@ import { socialLinkContainerStyle, } from "./footer.style"; import * as links from "../../constants/links"; +import * as img from "../../constants/img"; @Component({tag: "docs-footer", shadow: false}) export class DocsFooter { @@ -48,7 +49,7 @@ export class DocsFooter { - + {img.DISCORD.alt} diff --git a/client/src/amplify-ui/hero/__snapshots__/hero.spec.ts.snap b/client/src/docs-ui/hero/__snapshots__/hero.spec.ts.snap similarity index 65% rename from client/src/amplify-ui/hero/__snapshots__/hero.spec.ts.snap rename to client/src/docs-ui/hero/__snapshots__/hero.spec.ts.snap index 5b650b62f94..1a8d0cda57a 100644 --- a/client/src/amplify-ui/hero/__snapshots__/hero.spec.ts.snap +++ b/client/src/docs-ui/hero/__snapshots__/hero.spec.ts.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`amplify-hero Render logic should render 1`] = ` - +exports[`docs-hero Render logic should render 1`] = ` +

Heading @@ -10,5 +10,5 @@ exports[`amplify-hero Render logic should render 1`] = ` Subheading

-
+ `; diff --git a/client/src/amplify-ui/hero/hero.spec.ts b/client/src/docs-ui/hero/hero.spec.ts similarity index 72% rename from client/src/amplify-ui/hero/hero.spec.ts rename to client/src/docs-ui/hero/hero.spec.ts index 27999aa9569..7e4fa312fc8 100644 --- a/client/src/amplify-ui/hero/hero.spec.ts +++ b/client/src/docs-ui/hero/hero.spec.ts @@ -1,19 +1,19 @@ -import {AmplifyHero} from "./hero"; +import {DocsHero} from "./hero"; import {newSpecPage} from "@stencil/core/testing"; -describe("amplify-hero", () => { +describe("docs-hero", () => { describe("Render logic", () => { it("should render", async () => { expect( ( await newSpecPage({ - components: [AmplifyHero], + components: [DocsHero], html: ` - +

Heading

Subheading

-
+ `, }) ).root, diff --git a/client/src/amplify-ui/hero/hero.style.ts b/client/src/docs-ui/hero/hero.style.ts similarity index 100% rename from client/src/amplify-ui/hero/hero.style.ts rename to client/src/docs-ui/hero/hero.style.ts diff --git a/client/src/amplify-ui/hero/hero.tsx b/client/src/docs-ui/hero/hero.tsx similarity index 78% rename from client/src/amplify-ui/hero/hero.tsx rename to client/src/docs-ui/hero/hero.tsx index a03b7f452f2..3c993475588 100644 --- a/client/src/amplify-ui/hero/hero.tsx +++ b/client/src/docs-ui/hero/hero.tsx @@ -1,8 +1,8 @@ import {Component, h, Host} from "@stencil/core"; import {heroStyle} from "./hero.style"; -@Component({tag: "amplify-hero", shadow: false}) -export class AmplifyHero { +@Component({tag: "docs-hero", shadow: false}) +export class DocsHero { render() { return ( diff --git a/client/src/docs-ui/links-banner/__snapshots__/link-banner.spec.ts.snap b/client/src/docs-ui/links-banner/__snapshots__/link-banner.spec.ts.snap index 7d38f308198..26f54ce4255 100644 --- a/client/src/docs-ui/links-banner/__snapshots__/link-banner.spec.ts.snap +++ b/client/src/docs-ui/links-banner/__snapshots__/link-banner.spec.ts.snap @@ -8,7 +8,7 @@ exports[`docs-link-banner Render logic should render 1`] = ` Amplify GitHub
- + Discord Logo Amplify on Discord diff --git a/client/src/docs-ui/links-banner/link-banner.tsx b/client/src/docs-ui/links-banner/link-banner.tsx index 38044c79e90..313b1222799 100644 --- a/client/src/docs-ui/links-banner/link-banner.tsx +++ b/client/src/docs-ui/links-banner/link-banner.tsx @@ -5,6 +5,7 @@ import { logoStyle, } from "./link-banner.style"; import * as links from "../../constants/links"; +import * as img from "../../constants/img"; @Component({tag: "docs-link-banner", shadow: false}) export class DocsLinkBanner { @@ -19,7 +20,11 @@ export class DocsLinkBanner { Amplify GitHub - + {img.DISCORD.alt} Amplify on Discord diff --git a/client/src/docs-ui/page/__snapshots__/page.spec.ts.snap b/client/src/docs-ui/page/__snapshots__/page.spec.ts.snap index 8dfb82336c4..4d5e5dda445 100644 --- a/client/src/docs-ui/page/__snapshots__/page.spec.ts.snap +++ b/client/src/docs-ui/page/__snapshots__/page.spec.ts.snap @@ -1,3 +1,32 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`docs-page Render logic should render 1`] = ``; +exports[`docs-page Render logic should render 1`] = ` + + + +
+ + + + +

+

+ +
+ + + + +
+
+
+ +
+
+
+
+
+ + +
+`; diff --git a/client/src/docs-ui/page/page.tsx b/client/src/docs-ui/page/page.tsx index 7884f4e349a..1870a46a29b 100644 --- a/client/src/docs-ui/page/page.tsx +++ b/client/src/docs-ui/page/page.tsx @@ -237,7 +237,7 @@ export class DocsPage { }; render() { - if (Build.isBrowser) { + if (Build.isBrowser || location.pathname === "/") { return ( +
+
+ + search +
+
+ +`; diff --git a/client/src/docs-ui/search-bar/search-bar.spec.ts b/client/src/docs-ui/search-bar/search-bar.spec.ts new file mode 100644 index 00000000000..fb5d66051d7 --- /dev/null +++ b/client/src/docs-ui/search-bar/search-bar.spec.ts @@ -0,0 +1,17 @@ +import {DocsSearchBar} from "./search-bar"; +import {newSpecPage} from "@stencil/core/testing"; + +describe("docs-search-bar", () => { + describe("Render logic", () => { + it("should render", async () => { + expect( + ( + await newSpecPage({ + components: [DocsSearchBar], + html: ``, + }) + ).root, + ).toMatchSnapshot(); + }); + }); +}); diff --git a/client/src/docs-ui/search-bar/search-bar.style.ts b/client/src/docs-ui/search-bar/search-bar.style.ts new file mode 100644 index 00000000000..737a63b7a3e --- /dev/null +++ b/client/src/docs-ui/search-bar/search-bar.style.ts @@ -0,0 +1,82 @@ +import {MQLaptop} from "../../amplify-ui/styles/media"; +import {css} from "emotion"; + +// we use !important to override webkit's imposed border-radius +export const searchStyle = css` + width: 100%; + ${MQLaptop} { + width: initial; + } + .algolia-autocomplete .ds-dropdown-menu { + min-width: initial; + ${MQLaptop} { + min-width: 31.25rem; + } + } + > div { + width: 100%; + > div { + display: flex; + flex: 1; + flex-direction: row; + align-items: center; + position: relative; + .algolia-autocomplete { + display: block; + width: 100%; + } + .algolia-autocomplete .ds-dropdown-menu * { + white-space: normal; + } + .algolia-autocomplete + .algolia-docsearch-suggestion--subcategory-column-text { + white-space: normal; + } + .algolia-autocomplete + .algolia-docsearch-suggestion--content + > .algolia-docsearch-suggestion--text + > .algolia-docsearch-suggestion--highlight { + box-shadow: inset 0 -2px 0 0 var(--color-orange-hv); + } + .algolia-autocomplete .algolia-docsearch-suggestion--title { + font-weight: bold; + color: black; + } + .algolia-autocomplete .algolia-docsearch-suggestion--text { + font-size: 0.8rem; + color: gray; + } + .ds-cursor .algolia-docsearch-suggestion--content { + background-color: var(--bg-color-hover) !important; + } + .algolia-autocomplete .algolia-docsearch-suggestion--highlight { + color: var(--color-orange-hv); + background: var(--bg-color-hover); + } + .algolia-docsearch-suggestion--category-header-lvl0 { + color: initial; + } + .algolia-docsearch-suggestion--subcategory-column-text { + color: initial; + } + input { + position: relative; + display: flex; + flex: 1; + width: 100%; + height: 2rem; + border-radius: 0.25rem !important; + padding: 0 1.75rem 0 0.75rem; + min-width: 15rem; + -webkit-appearance: none; + appearance: none; + } + img { + position: absolute; + right: 0.5rem; + width: 0.75rem; + opacity: 0.5; + } + } + } +`; diff --git a/client/src/docs-ui/search-bar/search-bar.tsx b/client/src/docs-ui/search-bar/search-bar.tsx new file mode 100644 index 00000000000..e0c6de1f706 --- /dev/null +++ b/client/src/docs-ui/search-bar/search-bar.tsx @@ -0,0 +1,48 @@ +import {Component, Host, h, Build, Element} from "@stencil/core"; +import {searchStyle} from "./search-bar.style"; +import {transformData} from "../../utils/transform-search-data"; +import { + ALGOLIA_API_KEY, + ALGOLIA_INDEX_NAME, + UNINITIALIZED_SEARCH_INPUT_SELECTOR, +} from "../../constants/algolia"; + +@Component({tag: "docs-search-bar", shadow: false}) +export class DocsSearchBar { + @Element() element: HTMLElement; + + initDocSearch() { + if (Build.isBrowser) { + // @ts-ignore + docsearch({ + apiKey: ALGOLIA_API_KEY, + indexName: ALGOLIA_INDEX_NAME, + inputSelector: UNINITIALIZED_SEARCH_INPUT_SELECTOR, + debug: false, + transformData, + }); + } + } + + componentDidLoad() { + this.initDocSearch(); + } + + render() { + return ( + +
+
+ + search +
+
+
+ ); + } +} diff --git a/client/src/docs-ui/secondary-nav/__snapshots__/secondary-nav.spec.ts.snap b/client/src/docs-ui/secondary-nav/__snapshots__/secondary-nav.spec.ts.snap index 6c3f3f77d4a..5c1cbfc8a19 100644 --- a/client/src/docs-ui/secondary-nav/__snapshots__/secondary-nav.spec.ts.snap +++ b/client/src/docs-ui/secondary-nav/__snapshots__/secondary-nav.spec.ts.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`docs-secondary-nav Render logic should render 1`] = ` - +
@@ -34,14 +34,6 @@ exports[`docs-secondary-nav Render logic should render 1`] = `
-
-
-
- - search -
-
-
diff --git a/client/src/docs-ui/secondary-nav/secondary-nav.style.ts b/client/src/docs-ui/secondary-nav/secondary-nav.style.ts index 28499c67d49..50b012d7dc8 100644 --- a/client/src/docs-ui/secondary-nav/secondary-nav.style.ts +++ b/client/src/docs-ui/secondary-nav/secondary-nav.style.ts @@ -1,5 +1,5 @@ import {css} from "emotion"; -import {MQLaptop} from "../../amplify-ui/styles/media"; +import {MQLaptop, MQTablet, MQMobile} from "../../amplify-ui/styles/media"; export const secondaryNavStyle = css` display: flex; @@ -75,104 +75,12 @@ export const hostStyle = css` position: sticky; top: 0; background-color: var(--bg-color-secondary); - padding-bottom: 1rem; - ${MQLaptop} { + ${MQTablet} { padding: 0; } `; -// we use !important to override webkit's imposed border-radius -export const searchStyle = css` - width: 100%; - - ${MQLaptop} { - width: initial; - margin: 0 1rem; - } - - .algolia-autocomplete .ds-dropdown-menu { - min-width: initial; - - ${MQLaptop} { - min-width: 500px; - } - } - - > div { - width: 100%; - padding: 0 1rem; - - > div { - display: flex; - flex: 1; - flex-direction: row; - align-items: center; - position: relative; - - .algolia-autocomplete { - display: block; - width: 100%; - } - - .algolia-autocomplete .ds-dropdown-menu * { - white-space: normal; - } - - .algolia-autocomplete - .algolia-docsearch-suggestion--subcategory-column-text { - white-space: normal; - } - - .algolia-autocomplete - .algolia-docsearch-suggestion--content - > .algolia-docsearch-suggestion--text - > .algolia-docsearch-suggestion--highlight { - box-shadow: inset 0 -2px 0 0 var(--color-orange-hv); - } - - .algolia-autocomplete .algolia-docsearch-suggestion--title { - font-weight: bold; - color: black; - } - - .algolia-autocomplete .algolia-docsearch-suggestion--text { - font-size: 0.8rem; - color: gray; - } - - .ds-cursor .algolia-docsearch-suggestion--content { - background-color: var(--bg-color-hover) !important; - } - - .algolia-autocomplete .algolia-docsearch-suggestion--highlight { - color: var(--color-orange-hv); - background: var(--bg-color-hover); - } - - input { - position: relative; - display: flex; - flex: 1; - width: 100%; - height: 2rem; - border-radius: 0.25rem !important; - padding: 0 1.75rem 0 0.75rem; - min-width: 15rem; - -webkit-appearance: none; - appearance: none; - } - - img { - position: absolute; - right: 0.5rem; - width: 0.75rem; - opacity: 0.5; - } - } - } -`; - export const ghostItemStyle = css` display: block; width: 1rem; diff --git a/client/src/docs-ui/secondary-nav/secondary-nav.tsx b/client/src/docs-ui/secondary-nav/secondary-nav.tsx index 4cff43d4436..41170845ced 100644 --- a/client/src/docs-ui/secondary-nav/secondary-nav.tsx +++ b/client/src/docs-ui/secondary-nav/secondary-nav.tsx @@ -1,35 +1,25 @@ -import {Component, Host, h, Prop, Build} from "@stencil/core"; +import {Component, Host, h, Prop, State, Listen} from "@stencil/core"; import { secondaryNavStyle, hostStyle, - searchStyle, linkActiveStyle, shadowStyle, } from "./secondary-nav.style"; import {createVNodeFromHyperscriptNode} from "../../utils/hyperscript"; import {pageContext} from "../page/page.context"; import {SelectedFilters} from "../page/page.types"; -import {transformData} from "../../utils/transform-search-data"; -import * as links from "../../constants/links"; +import { + AWS_USER_GUIDE, + IOS_REFERENCE, + ANDROID_REFERENCE, + JS_REFERENCE, +} from "../../constants/links"; @Component({tag: "docs-secondary-nav", shadow: false}) export class DocsSecondaryNav { /*** the current filter state */ @Prop() readonly selectedFilters?: SelectedFilters; - componentDidRender() { - if (Build.isBrowser && location.pathname !== "/") { - // @ts-ignore - docsearch({ - apiKey: "24d37f059982b2f5ecf829afe93aed40", - indexName: "aws_amplify_new", - inputSelector: "#amplify-docs-search-input", - debug: false, - transformData, - }); - } - } - render() { return ( @@ -58,7 +48,7 @@ export class DocsSecondaryNav { }, { label: "Console", - url: links.AWS_USER_GUIDE, + url: AWS_USER_GUIDE, external: true, }, ...(this.selectedFilters?.platform @@ -68,13 +58,13 @@ export class DocsSecondaryNav { url: (() => { switch (this.selectedFilters.platform) { case "ios": { - return links.IOS_REFERENCE; + return IOS_REFERENCE; } case "android": { - return links.ANDROID_REFERENCE; + return ANDROID_REFERENCE; } case "js": { - return links.JS_REFERENCE; + return JS_REFERENCE; } } })(), @@ -101,19 +91,6 @@ export class DocsSecondaryNav {
-
-
-
- - search -
-
-
diff --git a/client/src/docs-ui/universal-nav/__snapshots__/universal-nav.spec.ts.snap b/client/src/docs-ui/universal-nav/__snapshots__/universal-nav.spec.ts.snap index 9c82bf9f1cc..84382ae3a53 100644 --- a/client/src/docs-ui/universal-nav/__snapshots__/universal-nav.spec.ts.snap +++ b/client/src/docs-ui/universal-nav/__snapshots__/universal-nav.spec.ts.snap @@ -3,15 +3,16 @@ exports[`docs-universal-nav Render logic should render 1`] = ` -
- +
+ NEW -
+ +
Community diff --git a/client/src/docs-ui/universal-nav/universal-nav.style.ts b/client/src/docs-ui/universal-nav/universal-nav.style.ts index eed9884e571..655f799c2fd 100644 --- a/client/src/docs-ui/universal-nav/universal-nav.style.ts +++ b/client/src/docs-ui/universal-nav/universal-nav.style.ts @@ -1,5 +1,5 @@ import {css} from "emotion"; -import {MQFablet} from "../../amplify-ui/styles/media"; +import {MQFablet, MQTablet, MQLaptop} from "../../amplify-ui/styles/media"; export const universalNavStyle = css` display: block; @@ -12,10 +12,14 @@ export const universalNavContentStyle = css` flex-direction: row; justify-content: space-between; align-items: center; - height: 4.5rem; width: 100%; transition: 0.25s ease all; - padding: 0 0rem 0 1.5rem; + padding: 1.5rem; + flex-wrap: wrap; + + > * { + flex: 1; + } span { color: var(--color-white); @@ -36,6 +40,13 @@ export const universalNavContentStyle = css` `; export const brandStyle = css` + order: 1; + width: 50%; + + ${MQTablet} { + margin-right: 3rem; + } + > a { display: flex; flex-direction: row; @@ -45,7 +56,7 @@ export const brandStyle = css` height: 1rem; margin-right: 0.125rem; - ${MQFablet} { + ${MQTablet} { height: 1.25rem; } } @@ -54,7 +65,7 @@ export const brandStyle = css` margin-left: 0.25rem; font-size: 1rem; - ${MQFablet} { + ${MQTablet} { font-size: 1.25rem; } } @@ -70,10 +81,29 @@ export const brandStyle = css` } `; +export const searchStyle = css` + width: 100%; + order: 3; + margin-top: 1.5rem; + flex: auto; + ${MQTablet} { + flex: 1 15rem; + order: 2; + margin: 0; + } +`; + export const linksStyle = css` display: flex; flex-direction: row; - padding-right: 1.5rem; + justify-content: flex-end; + order: 2; + width: 50%; + + ${MQTablet} { + margin-left: 3rem; + order: 3; + } a { display: flex; diff --git a/client/src/docs-ui/universal-nav/universal-nav.tsx b/client/src/docs-ui/universal-nav/universal-nav.tsx index 879492108be..600620ca453 100644 --- a/client/src/docs-ui/universal-nav/universal-nav.tsx +++ b/client/src/docs-ui/universal-nav/universal-nav.tsx @@ -1,12 +1,13 @@ -import {Component, h, Host, Prop} from "@stencil/core"; +import * as links from "../../constants/links"; +import {Component, h, Host, Prop, Listen, State} from "@stencil/core"; import { universalNavStyle, universalNavContentStyle, brandStyle, linksStyle, hideAboutLinkStyle, + searchStyle, } from "./universal-nav.style"; -import * as links from "../../constants/links"; @Component({tag: "docs-universal-nav", shadow: false}) export class DocsUniversalNav { @@ -44,6 +45,8 @@ export class DocsUniversalNav { NEW + +
+ diff --git a/client/src/utils/hyperscript/index.ts b/client/src/utils/hyperscript/index.ts index b355bdf9738..b67a73f4ef9 100644 --- a/client/src/utils/hyperscript/index.ts +++ b/client/src/utils/hyperscript/index.ts @@ -1,17 +1,10 @@ -import {h} from "@stencil/core"; -import {VNode} from "@stencil/core"; -import {isHTMLTagName} from "is-html-tag-name"; +import {h, VNode} from "@stencil/core"; export type Props = null | Record; export type OrText = T | string | number; export type HyperscriptNode = OrText<[string, Props, ...HyperscriptNode[]]>; export type HyperscriptResult = OrText; -export const validateTagName = (inQuestion: string) => - !isHTMLTagName(inQuestion) && - inQuestion.split("-").length < 2 && - console.error(`Invalid tag name: "${inQuestion}"`); - type CreateVNodeArgs = [string, Props, ...HyperscriptResult[]]; export const createVNode = (h as any) as ( ..._0: CreateVNodeArgs @@ -22,7 +15,6 @@ export const createVNodeFromHyperscriptNode = ( ): HyperscriptResult => { if (Array.isArray(node)) { const [tag, props, ...childHyperscriptNodes] = node; - validateTagName(tag); const childVNodes = createVNodesFromHyperscriptNodes(childHyperscriptNodes); return createVNode(tag, props, ...childVNodes); } diff --git a/client/stencil.config.ts b/client/stencil.config.ts index 7dd4b490d79..6d5cc7d7c68 100644 --- a/client/stencil.config.ts +++ b/client/stencil.config.ts @@ -69,7 +69,7 @@ export const config: Config = { unregister: true, }, baseUrl: "https://docs.amplify.aws", - prerenderConfig: "prerender-config.js", + prerenderConfig: "prerender.config.ts", copy: [ { src: "sitemap.xml", diff --git a/docs/cli/graphql-transformer/directives.md b/docs/cli/graphql-transformer/directives.md index 4dc1ea24cc3..e317770e6a0 100644 --- a/docs/cli/graphql-transformer/directives.md +++ b/docs/cli/graphql-transformer/directives.md @@ -955,7 +955,7 @@ type Profile @model @auth(rules: [{ allow: owner, provider: oidc, identityClaim: By using a configured `oidc` provider for the API, it is possible to authenticate the users against it to perform operations on the `Post` type, and `owner` authorization is also possible. -### Combining multiple authorization rules +### Combining multiple authorization types Amplify GraphQL APIs have a primary **default** authentication type and, optionally, additional secondary authentication types. The objects and fields in the GraphQL schema can have rules with different authorization providers assigned based on the authentication types configured in your app. @@ -969,8 +969,10 @@ type Post @model rules: [ # allow all authenticated users ability to create posts # allow owners ability to update and delete their posts + { allow: owner }, + # allow all authenticated users to read posts - { allow: owner, operations: [create, update, delete] }, + { allow: private, operations: [read] }, # allow all guest users (not authenticated) to read posts { allow: public, operations: [read] } diff --git a/docs/cli/graphql-transformer/relational.md b/docs/cli/graphql-transformer/relational.md index aee804c1468..f0d94e08d51 100644 --- a/docs/cli/graphql-transformer/relational.md +++ b/docs/cli/graphql-transformer/relational.md @@ -14,47 +14,48 @@ amplify add api **Go to the AWS RDS console and click "Create database".** +**Select "Standard Create" for the database creation method** -![Create cluster](~/images/create-database.png) +![Database Creation](~/images/database-creation.png) +**For Engine Options keep the following options** -**Select "Serverless" for the capacity type and fill in some information.** +![Engine Option](~/images/database-engine-option.png) +**Select "Serverless" in Database Features** -![Database details](~/images/database-details.png) +![Database Features](~/images/database-features.png) +**In Settings fill in the following information** -**Click next and configure any advanced settings. Click "Create database"** +![Database Settings](~/images/database-setting.png) -![Database details](~/images/configure-database.png) +**Select the Capacity Settings as shown below** +![Database Capacity](~/images/database-capacity.png) -**After creating the database, wait for the "Modify" button to become clickable. When ready, click "Modify" and scroll down to enable the "Data API"** +**Expand the "Additional connectivity configuration" and enable "Data API" and "Create New" if you do not have a VPC security group configured** -![Database details](~/images/data-api.png) +![Database Connectivity](~/images/database-connectivity.png) -**Click continue, verify the changes and apply them immediately. Click "Modify cluster"** +**Expand "Additional Configuration" and fill in "Initial Database Name" as MarketPlace** +![Database Additional Configuration](~/images/database-additional-configuration.png) -![Database details](~/images/modify-after-data-api.png) +**Click "Create Database" and dialog will open that will prompt you to connect select the cluster and fill in the credentials configured earlier** - -**Next click on "Query Editor" in the left nav bar and fill in connection information when prompted.** - - -![Database details](~/images/connect-to-db-from-queries.png) +![Database Connect ](~/images/connect-to-database.png) **After connecting, create a database and some tables.** -![Database details](~/images/create-a-database-and-schema.png) +![Database details](~/images/query-editor.png) ```sql -CREATE DATABASE MarketPlace; USE MarketPlace; CREATE TABLE Customers ( id int(11) NOT NULL PRIMARY KEY, diff --git a/docs/cli/hosting/hosting.md b/docs/cli/hosting/hosting.md index 0f9da3697fa..3a211c25ea6 100644 --- a/docs/cli/hosting/hosting.md +++ b/docs/cli/hosting/hosting.md @@ -35,6 +35,8 @@ If you select Amplify Console for hosting your Amplify App in the `amplify add h - **Continuous deployment** allows you to publish changes on every code commit by connecting your GitHub, Bitbucket, GitLab, or AWS CodeCommit repositories. Selecting this option would open up your AWS Amplify console where you can connect your Git repository. Once your repository is connected, run `git push` to deploy changes to both your backend and frontend in a single workflow. - **Manual deployment** allows you to publish your web app to the Amplify Console without connecting a Git provider. If you select this option, you will have to run the `amplify publish` command every time you would like to see your changes reflected in the cloud. +In order to change deployment types, you need to run `amplify remove hosting` and then `amplify add hosting` to choose your new preferred deployment type. + ### Custom domain, redirects, and more The `amplify configure hosting` command for the Amplify Console option, opens up the AWS Amplify Console browser tab for you where you can configure settings such as rewrite/redirect URL's, password protection, custom domain. diff --git a/docs/cli/start/workflows.md b/docs/cli/start/workflows.md index b197f76390f..3b1934b3328 100644 --- a/docs/cli/start/workflows.md +++ b/docs/cli/start/workflows.md @@ -39,8 +39,8 @@ During the init process, the root stack is created with three resources: The provider logs the information of the root stack and the resources into the project metadata file (amplify/backend/amplify-meta.json). The root stack's template can be found in `amplify/backend/awscloudformation`. -### amplify add -Once init is complete, run the command `amplify add` to add resources of a category to the cloud. This will place a CloudFormation template for the resources of this category in the category's subdirectory `amplify/backend/` and insert its reference into the above-mentioned root stack as the nested child stack. When working in teams, it is good practice to run an `amplify pull` before modifying the backend categories. +### amplify \ add +Once init is complete, run the command `amplify \ add` to add resources of a category to the cloud. This will place a CloudFormation template for the resources of this category in the category's subdirectory `amplify/backend/\` and insert its reference into the above-mentioned root stack as the nested child stack. When working in teams, it is good practice to run an `amplify pull` before modifying the backend categories. ### amplify push Once you have made your category updates, run the command `amplify push` to update the cloud resources. The CLI will first upload the latest versions of the category nested stack templates to the S3 deployment bucket, and then call the AWS CloudFormation API to create / update resources in the cloud. Based upon the resources added/updated, the `aws-exports.js` file (for JS projects) and the `awsconfiguration.json` file (for native projects) gets created/updated. diff --git a/docs/cli/teams/commands.md b/docs/cli/teams/commands.md index f1705226c2a..1aaa41af3b1 100644 --- a/docs/cli/teams/commands.md +++ b/docs/cli/teams/commands.md @@ -7,9 +7,9 @@ description: Use these Amplify CLI commands to manage a team workflow with multi Adds a new environment to your Amplify Project * amplify env list [--details] [--json]
Displays a list of all the environments in your Amplify project -* amplify env remove
+* amplify env remove \
Removes an environment from the Amplify project -* amplify env get --name
+* amplify env get --name \
Displays the details of the environment specified in the command * amplify env pull
Pulls your environment from the cloud without impacting any local backend edits. Add the `--restore` flag to overwrite your local backend edits (operates like the `amplify pull` command). diff --git a/docs/docs.md b/docs/docs.md index 78b93949735..edfdfbadd35 100644 --- a/docs/docs.md +++ b/docs/docs.md @@ -5,7 +5,7 @@ noTemplate: true disableLinkification: true --- - +

Amplify Framework Documentation

@@ -14,7 +14,7 @@ disableLinkification: true and web apps

-
+ diff --git a/docs/images/add-graphql-datasource.png b/docs/images/add-graphql-datasource.png old mode 100755 new mode 100644 index c092af78bd9..d793e3716b5 Binary files a/docs/images/add-graphql-datasource.png and b/docs/images/add-graphql-datasource.png differ diff --git a/docs/images/browser-published.png b/docs/images/browser-published.png index 2e550705385..b46fedbf71c 100644 Binary files a/docs/images/browser-published.png and b/docs/images/browser-published.png differ diff --git a/docs/images/configure-database.png b/docs/images/configure-database.png deleted file mode 100755 index 05718404c98..00000000000 Binary files a/docs/images/configure-database.png and /dev/null differ diff --git a/docs/images/connect-to-database.png b/docs/images/connect-to-database.png new file mode 100644 index 00000000000..c3bb4a021d1 Binary files /dev/null and b/docs/images/connect-to-database.png differ diff --git a/docs/images/connect-to-db-from-queries.png b/docs/images/connect-to-db-from-queries.png deleted file mode 100755 index f79683b3380..00000000000 Binary files a/docs/images/connect-to-db-from-queries.png and /dev/null differ diff --git a/docs/images/create-a-database-and-schema.png b/docs/images/create-a-database-and-schema.png deleted file mode 100755 index a548a0197d5..00000000000 Binary files a/docs/images/create-a-database-and-schema.png and /dev/null differ diff --git a/docs/images/create-database.png b/docs/images/create-database.png deleted file mode 100755 index 2ab75c8a885..00000000000 Binary files a/docs/images/create-database.png and /dev/null differ diff --git a/docs/images/data-api.png b/docs/images/data-api.png deleted file mode 100755 index d256d849804..00000000000 Binary files a/docs/images/data-api.png and /dev/null differ diff --git a/docs/images/database-additional-configuration.png b/docs/images/database-additional-configuration.png new file mode 100644 index 00000000000..83e7f2fdc1b Binary files /dev/null and b/docs/images/database-additional-configuration.png differ diff --git a/docs/images/database-capacity.png b/docs/images/database-capacity.png new file mode 100644 index 00000000000..d41b571cc46 Binary files /dev/null and b/docs/images/database-capacity.png differ diff --git a/docs/images/database-connectivity.png b/docs/images/database-connectivity.png new file mode 100644 index 00000000000..b41c86cd72f Binary files /dev/null and b/docs/images/database-connectivity.png differ diff --git a/docs/images/database-creation.png b/docs/images/database-creation.png new file mode 100644 index 00000000000..8a4daeaf39a Binary files /dev/null and b/docs/images/database-creation.png differ diff --git a/docs/images/database-details.png b/docs/images/database-details.png deleted file mode 100755 index f837b7a8a19..00000000000 Binary files a/docs/images/database-details.png and /dev/null differ diff --git a/docs/images/database-engine-option.png b/docs/images/database-engine-option.png new file mode 100644 index 00000000000..cb704de5f63 Binary files /dev/null and b/docs/images/database-engine-option.png differ diff --git a/docs/images/database-features.png b/docs/images/database-features.png new file mode 100644 index 00000000000..00b58aaa270 Binary files /dev/null and b/docs/images/database-features.png differ diff --git a/docs/images/database-setting.png b/docs/images/database-setting.png new file mode 100644 index 00000000000..661249e6d7a Binary files /dev/null and b/docs/images/database-setting.png differ diff --git a/docs/images/identifiers.gif b/docs/images/identifiers.gif deleted file mode 100644 index fa13b4d7da7..00000000000 Binary files a/docs/images/identifiers.gif and /dev/null differ diff --git a/docs/images/modify-after-data-api.png b/docs/images/modify-after-data-api.png deleted file mode 100755 index 19973dd4a71..00000000000 Binary files a/docs/images/modify-after-data-api.png and /dev/null differ diff --git a/docs/images/query-editor.png b/docs/images/query-editor.png new file mode 100644 index 00000000000..a162c898bbb Binary files /dev/null and b/docs/images/query-editor.png differ diff --git a/docs/images/runningApp.gif b/docs/images/runningApp.gif deleted file mode 100644 index 365ab0113d2..00000000000 Binary files a/docs/images/runningApp.gif and /dev/null differ diff --git a/docs/lib/auth/fragments/android/escapehatch/10_awsmobileclient_escape.md b/docs/lib/auth/fragments/android/escapehatch/10_awsmobileclient_escape.md index a61ce792a74..53694cf418f 100644 --- a/docs/lib/auth/fragments/android/escapehatch/10_awsmobileclient_escape.md +++ b/docs/lib/auth/fragments/android/escapehatch/10_awsmobileclient_escape.md @@ -14,3 +14,19 @@ val mobileClient = Amplify.Auth.getPlugin("awsCognitoAuthPlugin").escapeHatch as + +You can use the escape hatch to `federatedSignIn` with a valid token from other social providers. Find more details [here](https://docs.amplify.aws/sdk/auth/federated-identities/q/platform/android) + +```java +mobileClient.federatedSignIn(IdentityProvider.FACEBOOK.toString(), "", new Callback() { + @Override + public void onResult(final UserStateDetails userStateDetails) { + //Handle the result + } + + @Override + public void onError(Exception e) { + Log.e(TAG, "sign-in error", e); + } +}); +``` \ No newline at end of file diff --git a/docs/lib/auth/fragments/ios/access_credentials/10_fetchAuthSession.md b/docs/lib/auth/fragments/ios/access_credentials/10_fetchAuthSession.md index dc03840c3b5..95558e0617e 100644 --- a/docs/lib/auth/fragments/ios/access_credentials/10_fetchAuthSession.md +++ b/docs/lib/auth/fragments/ios/access_credentials/10_fetchAuthSession.md @@ -1,7 +1,7 @@ ```swift import AWSPluginsCore -_ = Amplify.Auth.fetchAuthSession { (result) in +_ = Amplify.Auth.fetchAuthSession { result in do { let session = try result.get() diff --git a/docs/lib/auth/fragments/ios/device_features/10_rememberDevice.md b/docs/lib/auth/fragments/ios/device_features/10_rememberDevice.md index 36b2dcd8e95..324666bb0ea 100644 --- a/docs/lib/auth/fragments/ios/device_features/10_rememberDevice.md +++ b/docs/lib/auth/fragments/ios/device_features/10_rememberDevice.md @@ -1,10 +1,10 @@ ```swift -_ = Amplify.Auth.rememberDevice() { (result) in +_ = Amplify.Auth.rememberDevice() { result in switch result { case .success: - print("Remeber device succeeded") + print("Remember device succeeded") case .failure(let error): - print("Remeber device failed with error \(error)") + print("Remember device failed with error \(error)") } } -``` \ No newline at end of file +``` diff --git a/docs/lib/auth/fragments/ios/device_features/20_forgetDevice.md b/docs/lib/auth/fragments/ios/device_features/20_forgetDevice.md index a5d84a5bd24..43caac4eb96 100644 --- a/docs/lib/auth/fragments/ios/device_features/20_forgetDevice.md +++ b/docs/lib/auth/fragments/ios/device_features/20_forgetDevice.md @@ -1,5 +1,5 @@ ```swift -_ = Amplify.Auth.forgetDevice() {(result) in +_ = Amplify.Auth.forgetDevice() { result in switch result { case .success: print("Forget device succeeded") diff --git a/docs/lib/auth/fragments/ios/device_features/30_fetchDevice.md b/docs/lib/auth/fragments/ios/device_features/30_fetchDevice.md index 67bd3ca5066..f78a720df2c 100644 --- a/docs/lib/auth/fragments/ios/device_features/30_fetchDevice.md +++ b/docs/lib/auth/fragments/ios/device_features/30_fetchDevice.md @@ -1,5 +1,5 @@ ```swift -_ = Amplify.Auth.fetchDevices() { (result) in +_ = Amplify.Auth.fetchDevices() { result in switch result { case .success(let fetchDeviceResult): for device in fetchDeviceResult { diff --git a/docs/lib/auth/fragments/ios/escapehatch/10_awsmobileclient_escape.md b/docs/lib/auth/fragments/ios/escapehatch/10_awsmobileclient_escape.md index 43d25fd2e39..9cb5b212dd1 100644 --- a/docs/lib/auth/fragments/ios/escapehatch/10_awsmobileclient_escape.md +++ b/docs/lib/auth/fragments/ios/escapehatch/10_awsmobileclient_escape.md @@ -17,4 +17,23 @@ func getEscapeHatch() { } ``` -It is not recommened to use`AWSMobileClient` credentials apis like `getToken`, `getAWSCredentials` through the escape hatch object. \ No newline at end of file +It is not recommened to use`AWSMobileClient` credentials apis like `getToken`, `getAWSCredentials` through the escape hatch object. + +You can use the escape hatch to `federatedSignIn` with a valid token from other social providers. Find more details [here](https://docs.amplify.aws/sdk/auth/federated-identities/q/platform/ios) + +```swift +awsmobileclient.federatedSignIn(providerName: IdentityProvider.apple.rawValue, + token: "") { (userState, error) in + if let error = error { + print("Error in federatedSignIn: \(error)") + return + } + + guard let userState = userState else { + print("userState unexpectedly nil") + return + } + print("federatedSignIn successful: \(userState)") + +} +``` \ No newline at end of file diff --git a/docs/lib/auth/fragments/ios/getting_started/40_fetchSession.md b/docs/lib/auth/fragments/ios/getting_started/40_fetchSession.md index 2b3d317d3d0..c56dd3c4da8 100644 --- a/docs/lib/auth/fragments/ios/getting_started/40_fetchSession.md +++ b/docs/lib/auth/fragments/ios/getting_started/40_fetchSession.md @@ -1,6 +1,6 @@ ```swift func fetchCurrentAuthSession() { - _ = Amplify.Auth.fetchAuthSession { (result) in + _ = Amplify.Auth.fetchAuthSession { result in switch result { case .success(let session): print("Is user signed in - \(session.isSignedIn)") diff --git a/docs/lib/auth/fragments/ios/password_management/10_reset_password.md b/docs/lib/auth/fragments/ios/password_management/10_reset_password.md index 4da96f9baf8..39d620498e7 100644 --- a/docs/lib/auth/fragments/ios/password_management/10_reset_password.md +++ b/docs/lib/auth/fragments/ios/password_management/10_reset_password.md @@ -1,7 +1,7 @@ ```swift func resetPassword(username: String) { - _ = Amplify.Auth.resetPassword(for: username) {(result) in + _ = Amplify.Auth.resetPassword(for: username) { result in do { let resetResult = try result.get() diff --git a/docs/lib/auth/fragments/ios/password_management/20_confirm_reset_password.md b/docs/lib/auth/fragments/ios/password_management/20_confirm_reset_password.md index 68d07ca0fc7..bc7473b9410 100644 --- a/docs/lib/auth/fragments/ios/password_management/20_confirm_reset_password.md +++ b/docs/lib/auth/fragments/ios/password_management/20_confirm_reset_password.md @@ -6,8 +6,7 @@ func confirmResetPassword(username: String, _ = Amplify.Auth.confirmResetPassword( for: username, with: newPassword, - confirmationCode: confirmationCode) {(result) in - + confirmationCode: confirmationCode) { result in switch result { case .success: print("Password reset confirmed") diff --git a/docs/lib/auth/fragments/ios/signout/10_local_signout.md b/docs/lib/auth/fragments/ios/signout/10_local_signout.md index 59d995bfd34..e6e34c24e8e 100644 --- a/docs/lib/auth/fragments/ios/signout/10_local_signout.md +++ b/docs/lib/auth/fragments/ios/signout/10_local_signout.md @@ -1,5 +1,5 @@ ```swift -_ = Amplify.Auth.signOut() { (result) in +_ = Amplify.Auth.signOut() { result in switch result { case .success: print("Successfully signed out") diff --git a/docs/lib/auth/fragments/ios/signout/20_global_signout.md b/docs/lib/auth/fragments/ios/signout/20_global_signout.md index 6cc78a21578..b852d715e43 100644 --- a/docs/lib/auth/fragments/ios/signout/20_global_signout.md +++ b/docs/lib/auth/fragments/ios/signout/20_global_signout.md @@ -1,6 +1,6 @@ ```swift let options = AuthSignOutRequest.Options(globalSignOut: true) -_ = Amplify.Auth.signOut(options: options) { (result) in +_ = Amplify.Auth.signOut(options: options) { result in switch result { case .success: print("Successfully signed out") diff --git a/docs/lib/auth/fragments/ios/user_attributes/10_fetch_attributes.md b/docs/lib/auth/fragments/ios/user_attributes/10_fetch_attributes.md index 9c984230d9c..851894b985f 100644 --- a/docs/lib/auth/fragments/ios/user_attributes/10_fetch_attributes.md +++ b/docs/lib/auth/fragments/ios/user_attributes/10_fetch_attributes.md @@ -1,7 +1,7 @@ ```swift func fetchAttributes() { - _ = Amplify.Auth.fetchUserAttributes() { (result) in + _ = Amplify.Auth.fetchUserAttributes() { result in switch result { case .success(let attributes): print("User attribtues - \(attributes)") diff --git a/docs/lib/auth/fragments/ios/user_attributes/20_update_user_attribute.md b/docs/lib/auth/fragments/ios/user_attributes/20_update_user_attribute.md index 48a252f82ec..bb1040319c3 100644 --- a/docs/lib/auth/fragments/ios/user_attributes/20_update_user_attribute.md +++ b/docs/lib/auth/fragments/ios/user_attributes/20_update_user_attribute.md @@ -1,6 +1,6 @@ ```swift func updateAttribute() { - _ = Amplify.Auth.update(userAttribute: AuthUserAttribute(.phoneNumber, value: "+2223334444")) { (result) in + _ = Amplify.Auth.update(userAttribute: AuthUserAttribute(.phoneNumber, value: "+2223334444")) { result in do { let updateResult = try result.get() diff --git a/docs/lib/auth/fragments/ios/user_attributes/30_confirm_attribute.md b/docs/lib/auth/fragments/ios/user_attributes/30_confirm_attribute.md index dd1cbc87091..33f111e7b18 100644 --- a/docs/lib/auth/fragments/ios/user_attributes/30_confirm_attribute.md +++ b/docs/lib/auth/fragments/ios/user_attributes/30_confirm_attribute.md @@ -1,6 +1,6 @@ ```swift func confirmAttribute() { - _ = Amplify.Auth.confirm(userAttribute: .email, confirmationCode: "390739") { (result) in + _ = Amplify.Auth.confirm(userAttribute: .email, confirmationCode: "390739") { result in switch result { case .success: print("Attribute verified") diff --git a/docs/lib/auth/fragments/ios/user_attributes/40_resend_code.md b/docs/lib/auth/fragments/ios/user_attributes/40_resend_code.md index 537e4500af6..972073736b7 100644 --- a/docs/lib/auth/fragments/ios/user_attributes/40_resend_code.md +++ b/docs/lib/auth/fragments/ios/user_attributes/40_resend_code.md @@ -1,6 +1,6 @@ ```swift func resendCode() { - _ = Amplify.Auth.resendConfirmationCode(for: .email) {(result) in + _ = Amplify.Auth.resendConfirmationCode(for: .email) { result in switch result { case .success(let deliveryDetails): print("Resend code send to - \(deliveryDetails)") diff --git a/docs/lib/auth/fragments/native_common/escape_hatch/common.md b/docs/lib/auth/fragments/native_common/escape_hatch/common.md index 387cc3acffa..6460d76b16d 100644 --- a/docs/lib/auth/fragments/native_common/escape_hatch/common.md +++ b/docs/lib/auth/fragments/native_common/escape_hatch/common.md @@ -6,4 +6,4 @@ The return type and behavior of the escape hatch is an implementation detail and - + \ No newline at end of file diff --git a/docs/lib/graphqlapi/authz.md b/docs/lib/graphqlapi/authz.md index 2eb5183e314..e54cfb26c87 100644 --- a/docs/lib/graphqlapi/authz.md +++ b/docs/lib/graphqlapi/authz.md @@ -3,6 +3,6 @@ title: Configure authorization modes description: Learn more about how to configure authorization modes in Amplify Framework's API category --- - - + + diff --git a/docs/lib/graphqlapi/fragments/android/authz.md b/docs/lib/graphqlapi/fragments/android/authz.md deleted file mode 100644 index 8244723fdaf..00000000000 --- a/docs/lib/graphqlapi/fragments/android/authz.md +++ /dev/null @@ -1,135 +0,0 @@ -For client authorization AppSync supports API Keys, Amazon IAM credentials, Amazon Cognito User Pools, and 3rd party OIDC providers. This is inferred from the `amplifyconfiguration.json` file when you call `Amplify.configure()`. - -## API Key - -API Key is the easiest way to setup and prototype your application with AppSync. - -```json -{ - ... - "awsAPIPlugin": { - "` as the `apiName` parameter in the `Amplify.API` call to reference each authorization type. - -The following snippets highlight the new values in the `amplifyconfiguration.json` and the client code configurations. - -The `friendly_name` illustrated here is created from Amplify CLI prompt. There are 4 clients in this configuration that connect to the same API except that they use different `AuthMode`. - -```json -{ - "UserAgent": "aws-amplify-cli/2.0", - "Version": "1.0", - "api": { - "plugins": { - "awsAPIPlugin": { - "friendly_name_API_KEY": { - "endpointType": "GraphQL", - "endpoint": "https://xyz.appsync-api.us-west-2.amazonaws.com/graphql", - "region": "us-west-2", - "authorizationType": "API_KEY", - "apiKey": "da2-abcdefghijklmnopqr" - }, - "friendly_name_AWS_IAM": { - "endpointType": "GraphQL", - "endpoint": "https://xyz.appsync-api.us-west-2.amazonaws.com/graphql", - "region": "us-west-2", - "authorizationType": "API_IAM", - }, - "friendly_name_AMAZON_COGNITO_USER_POOLS": { - "endpointType": "GraphQL", - "endpoint": "https://xyz.appsync-api.us-west-2.amazonaws.com/graphql", - "region": "us-west-2", - "authorizationType": "AMAZON_COGNITO_USER_POOLS", - }, - "friendly_name_OPENID_CONNECT": { - "endpointType": "GraphQL", - "endpoint": "https://xyz.appsync-api.us-west-2.amazonaws.com/graphql", - "region": "us-west-2", - "authorizationType": "OPENID_CONNECT", - } - } - } - } -} -``` - -To invoke a named API: - -```java -Amplify.API.mutate("friendly_name_API_KEY" ...) -``` diff --git a/docs/lib/graphqlapi/fragments/android/authz/10_userpool.md b/docs/lib/graphqlapi/fragments/android/authz/10_userpool.md new file mode 100644 index 00000000000..4e5e688290b --- /dev/null +++ b/docs/lib/graphqlapi/fragments/android/authz/10_userpool.md @@ -0,0 +1,20 @@ +Add the following code to your app: + + + + +```java +Amplify.addPlugin(new AWSCognitoAuthPlugin()); +Amplify.addPlugin(new AWSApiPlugin()); +``` + + + + +```kotlin +Amplify.addPlugin(AWSCognitoAuthPlugin()) +Amplify.addPlugin(AWSApiPlugin()) +``` + + + diff --git a/docs/lib/graphqlapi/fragments/android/authz/20_oidc.md b/docs/lib/graphqlapi/fragments/android/authz/20_oidc.md new file mode 100644 index 00000000000..06470787e53 --- /dev/null +++ b/docs/lib/graphqlapi/fragments/android/authz/20_oidc.md @@ -0,0 +1,24 @@ +Add the following code to your app: + + + + +```java +ApiAuthProviders authProviders = ApiAuthProviders.builder() + .oidcAuthProvider(() -> "[OPEN-ID-CONNECT-TOKEN]") + .build(); +Amplify.addPlugin(new AWSApiPlugin(authProviders)); +``` + + + + +```kotlin +val authProviders = ApiAuthProviders.builder() + .oidcAuthProvider { "[OPEN-ID-CONNECT-TOKEN]" } + .build() +Amplify.addPlugin(AWSApiPlugin(authProviders)) +``` + + + diff --git a/docs/lib/graphqlapi/fragments/android/authz/30_multi.md b/docs/lib/graphqlapi/fragments/android/authz/30_multi.md new file mode 100644 index 00000000000..df6956af7a6 --- /dev/null +++ b/docs/lib/graphqlapi/fragments/android/authz/30_multi.md @@ -0,0 +1,28 @@ +When you have configured multiple APIs, you can specify the name of the API as a parameter as the target for an operation: + + + + +```java +Amplify.API.mutate( + "[FRIENDLY-NAME-API-WITH-API-KEY]", + request, + response -> Log.i("MyAmplifyApp", "Mutation successful"), + error -> Log.e("MyAmplifyApp", "Failed to mutate model.", error) +); +``` + + + + +```kotlin +Amplify.API.mutate( + "[FRIENDLY-NAME-API-WITH-API-KEY]", + request, + { Log.i("MyAmplifyApp", "Mutation successful") }, + { Log.e("MyAmplifyApp", "Failed to mutate model.", it) } +) +``` + + + diff --git a/docs/lib/graphqlapi/fragments/android/query-data.md b/docs/lib/graphqlapi/fragments/android/query-data.md index 30ad3c764b1..b2893a71e40 100644 --- a/docs/lib/graphqlapi/fragments/android/query-data.md +++ b/docs/lib/graphqlapi/fragments/android/query-data.md @@ -67,3 +67,64 @@ Amplify.API.query( + +> **Note**: This approach will only return up to the first 1,000 items. To change this limit or make requests for additional results beyond this limit, use *pagination* as discussed below. + +## List multiple pages of items + +Pagination allows you to request a maximum number of results to be returned in a response. To consume further results beyond that, you can request a next page of results, if available. + + + + +```java +public void queryFirstPage() { + query(ModelQuery.list(Todo.class, ModelPagination.firstPage().withLimit(1_000))); +} + +private static void query(GraphQLRequest> request) { + Amplify.API.query( + request, + response -> { + if (response.hasData()) { + for (Todo todo : response.getData().getItems()) { + Log.d("MyAmplifyApp", todo.getName()); + } + if (response.getData().hasNextResult()) { + query(response.getData().getRequestForNextResult()); + } + } + }, + failure -> Log.e("MyAmplifyApp", "Query failed.", failure) + ); +} +``` + + + + +```kotlin +fun queryFirstPage() { + query(ModelQuery.list(Todo::class.java, ModelPagination.firstPage().withLimit(1_000))) +} + +fun query(request: GraphQLRequest>) { + Amplify.API.query( + request, + { response -> + if (response.hasData()) { + for (todo in response.data.items) { + Log.d("MyAmplifyApp", todo.name) + } + if (response.data.hasNextResult()) { + query(response.data.requestForNextResult) + } + } + }, + { failure -> Log.e("MyAmplifyApp", "Query failed.", failure) } + ) +} +``` + + + diff --git a/docs/lib/graphqlapi/fragments/ios/authz.md b/docs/lib/graphqlapi/fragments/ios/authz.md deleted file mode 100644 index ac0922eed77..00000000000 --- a/docs/lib/graphqlapi/fragments/ios/authz.md +++ /dev/null @@ -1,215 +0,0 @@ -For client authorization AppSync supports API Keys, Amazon IAM credentials, Amazon Cognito User Pools, and 3rd party OIDC providers. This is inferred from the `amplifyconfiguration.json` file when you call `Amplify.configure()`. - -#### API Key - -API Key is the easiest way to setup and prototype your application with AppSync. - - -#### Cognito User Pools - -Amazon Cognito User Pools is the most common service to use with AppSync when adding user Sign-Up and Sign-In to your application. If your application needs to interact with other AWS services besides AppSync, such as S3, you will need to use IAM credentials with Cognito Identity Pools. The Amplify CLI can automatically configure this for you when running `amplify add auth` and can also automatically federate User Pools with Identity Pools. This allows you to have both User Pool credentials for AppSync and AWS credentials for S3. You can then use the `AWSMobileClient` for automatic credentials refresh [as outlined in the authentication section](~/sdk/auth/how-it-works.md). For manual configuration, add the following snippet to your `awsconfiguration.json` file: - -```json -{ - "CognitoUserPool": { - "Default": { - "PoolId": "POOL-ID", - "AppClientId": "APP-CLIENT-ID", - "AppClientSecret": "APP-CLIENT-SECRET", - "Region": "us-east-1" - } - }, - "AppSync": { - "Default": { - "ApiUrl": "YOUR-GRAPHQL-ENDPOINT", - "Region": "us-east-1", - "AuthMode": "AMAZON_COGNITO_USER_POOLS" - } - } -} -``` - -and your `amplifyconfiguration.json` file, under the `awsAPIPlugin` -```json -{ - ... - "awsAPIPlugin": { - " Bool { - // Override point for customization after application launch. - AWSMobileClient.default().initialize { (userState, error) in - guard error == nil else { - print("Error initializing AWSMobileClient. Error: \(error!.localizedDescription)") - return - } - guard let userState = userState else { - print("userState is unexpectedly empty initializing AWSMobileClient") - return - } - - print("AWSMobileClient initialized, userstate: \(userState)") - } - - // Amplify section - let apiPlugin = AWSAPIPlugin() - try! Amplify.add(plugin: apiPlugin) - try! Amplify.configure() - print("Amplify initialized") - - return true - } -``` - -#### IAM - -When using AWS IAM in a mobile application you should leverage Amazon Cognito Identity Pools. The Amplify CLI can automatically configure this for you when running `amplify add auth`. You can then use the `AWSMobileClient` for automatic credentials refresh [as outlined in the authentication section](~/sdk/auth/how-it-works.md) For manual configuration, add the following snippet to your `awsconfiguration.json` file: - -```json -{ - "CredentialsProvider": { - "CognitoIdentity": { - "Default": { - "PoolId": "YOUR-COGNITO-IDENTITY-POOLID", - "Region": "us-east-1" - } - } - } -} -``` - -and your `amplifyconfiguration.json` file, under the `awsAPIPlugin` -```json -{ - ... - "awsAPIPlugin": { - " URLRequest { - guard let mutableRequest = (request as NSURLRequest).mutableCopy() as? NSMutableURLRequest else { - throw APIError.unknown("Could not get mutable request", "") - } - mutableRequest.setValue(NSDate().aws_stringValue(AWSDateISO8601DateFormat2), forHTTPHeaderField: "X-Amz-Date") - mutableRequest.setValue("application/json", forHTTPHeaderField: "Content-Type") - mutableRequest.setValue("amplify-ios/0.0.1 Amplify", forHTTPHeaderField: "User-Agent") - - let token = "MyToken" - mutableRequest.setValue(token, forHTTPHeaderField: "authorization") - return mutableRequest as URLRequest - } -} - -do { - // Initialize Amplify with the interceptor - let apiPlugin = AWSAPIPlugin() - do { - try Amplify.add(plugin: apiPlugin) - try Amplify.configure() - print("Amplify initialized") - let interceptor = MyOidcURLRequestInterceptor() - try Amplify.API.add(interceptor: interceptor, for: "") - } catch { - print("Failed to configure Amplify \(error)") - } -} catch { - print("Error initializing appsync client. \(error)") -} -``` - -#### Multi-Auth - -This section talks about the capability of AWS AppSync to configure multiple authorization modes for a single AWS AppSync endpoint and region. Follow the [AWS AppSync Multi-Auth](https://docs.aws.amazon.com/appsync/latest/devguide/security.html#using-additional-authorization-modes) to configure multiple authorization modes for your AWS AppSync endpoint. - -You can now configure a single GraphQL API to deliver private and public data. Private data requires authenticated access using authorization mechanisms such as IAM, Cognito User Pools, and OIDC. Public data does not require authenticated access and is delivered through authorization mechanisms such as API Keys. You can also configure a single GraphQL API to deliver private data using more than one authorization type. For example, you can configure your GraphQL API to authorize some schema fields using OIDC, while other schema fields through Cognito User Pools and/or IAM. - -As discussed in the above linked documentation, certain fields may be protected by different authorization types. This can lead the same query, mutation, or subscription to have different responses based on the authorization sent with the request; Therefore, it is recommended to use the different `friendly_name_` as the `apiName` parameter in the `Amplify.API` call to reference each authorization type. - -The following snippets highlight the new values in the `amplifyconfiguration.json` and the client code configurations. - -The `friendly_name` illustrated here is created from Amplify CLI prompt. There are 4 clients in this configuration that connect to the same API except that they use different `AuthMode`. - -```json -{ - "UserAgent": "aws-amplify-cli/2.0", - "Version": "1.0", - "api": { - "plugins": { - "awsAPIPlugin": { - "friendly_name_API_KEY": { - "endpointType": "GraphQL", - "endpoint": "https://xyz.appsync-api.us-west-2.amazonaws.com/graphql", - "region": "us-west-2", - "authorizationType": "API_KEY", - "apiKey": "da2-abcdefghijklmnopqr" - }, - "friendly_name_AWS_IAM": { - "endpointType": "GraphQL", - "endpoint": "https://xyz.appsync-api.us-west-2.amazonaws.com/graphql", - "region": "us-west-2", - "authorizationType": "API_KEY", - }, - "friendly_name_AMAZON_COGNITO_USER_POOLS": { - "endpointType": "GraphQL", - "endpoint": "https://xyz.appsync-api.us-west-2.amazonaws.com/graphql", - "region": "us-west-2", - "authorizationType": "AMAZON_COGNITO_USER_POOLS", - }, - "friendly_name_OPENID_CONNECT": { - "endpointType": "GraphQL", - "endpoint": "https://xyz.appsync-api.us-west-2.amazonaws.com/graphql", - "region": "us-west-2", - "authorizationType": "OPENID_CONNECT", - } - } - } - } -} -``` - -```swift -Amplify.API.mutate(apiName: "friendly_name_API_KEY" ...) -``` \ No newline at end of file diff --git a/docs/lib/graphqlapi/fragments/ios/authz/10_userpool.md b/docs/lib/graphqlapi/fragments/ios/authz/10_userpool.md new file mode 100644 index 00000000000..2accd1995cf --- /dev/null +++ b/docs/lib/graphqlapi/fragments/ios/authz/10_userpool.md @@ -0,0 +1,12 @@ +Add the following code to your app: + +```swift + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + try! Amplify.add(plugin: AWSCognitoAuthPlugin()) + try! Amplify.add(plugin: AWSAPIPlugin()) + try! Amplify.configure() + print("Amplify initialized") + + return true + } +``` \ No newline at end of file diff --git a/docs/lib/graphqlapi/fragments/ios/authz/20_oidc.md b/docs/lib/graphqlapi/fragments/ios/authz/20_oidc.md new file mode 100644 index 00000000000..dfdb5e43feb --- /dev/null +++ b/docs/lib/graphqlapi/fragments/ios/authz/20_oidc.md @@ -0,0 +1,37 @@ + + +Add the following code to your app: + +```swift +public class MyOidcURLRequestInterceptor: URLRequestInterceptor { + + public func intercept(_ request: URLRequest) throws -> URLRequest { + guard let mutableRequest = (request as NSURLRequest).mutableCopy() as? NSMutableURLRequest else { + throw APIError.unknown("Could not get mutable request", "") + } + mutableRequest.setValue(NSDate().aws_stringValue(AWSDateISO8601DateFormat2), forHTTPHeaderField: "X-Amz-Date") + mutableRequest.setValue("application/json", forHTTPHeaderField: "Content-Type") + mutableRequest.setValue("amplify-ios/0.0.1 Amplify", forHTTPHeaderField: "User-Agent") + + let token = "MyToken" + mutableRequest.setValue(token, forHTTPHeaderField: "authorization") + return mutableRequest as URLRequest + } +} + +do { + // Initialize Amplify with the interceptor + let apiPlugin = AWSAPIPlugin() + do { + try Amplify.add(plugin: apiPlugin) + try Amplify.configure() + print("Amplify initialized") + let interceptor = MyOidcURLRequestInterceptor() + try Amplify.API.add(interceptor: interceptor, for: "") + } catch { + print("Failed to configure Amplify \(error)") + } +} catch { + print("Error initializing appsync client. \(error)") +} +``` diff --git a/docs/lib/graphqlapi/fragments/ios/authz/30_multi.md b/docs/lib/graphqlapi/fragments/ios/authz/30_multi.md new file mode 100644 index 00000000000..fb0a06897a5 --- /dev/null +++ b/docs/lib/graphqlapi/fragments/ios/authz/30_multi.md @@ -0,0 +1,6 @@ +When you have configured multiple APIs, you can specify the name of the API as a parameter as the target for an operation: + +```swift +let request = GraphQLRequest(apiName: "[FRIENDLY-NAME-API-WITH-API-KEY]", ...) +Amplify.API.mutate(request: request, listener: ...) +``` \ No newline at end of file diff --git a/docs/lib/graphqlapi/fragments/native_common/authz/common.md b/docs/lib/graphqlapi/fragments/native_common/authz/common.md new file mode 100644 index 00000000000..104947e01b2 --- /dev/null +++ b/docs/lib/graphqlapi/fragments/native_common/authz/common.md @@ -0,0 +1,155 @@ +For client authorization AppSync supports API Keys, Amazon IAM credentials, Amazon Cognito User Pools, and 3rd party OIDC providers. This is inferred from the `amplifyconfiguration.json` file when you call `Amplify.configure()`. + +#### API key + +API Key is the easiest way to setup and prototype your application with AWS AppSync. This means it is also prone to abuse since anyone can easily discover the API Key and make requests to your public service. To have authorization checks, use the other auth modes such as Cognito user pool or AWS IAM. API Key will expiry according to the expiry time set when provisioning AWS AppSync and will require extending it or creating a new one if needed. + +#### Amazon Cognito User Pools + +Amazon Cognito's user pool is most commonly used with AWS AppSync when adding authorization check on your API calls. If your application needs to interact with other AWS services besides AWS AppSync, such as Amazon S3, you will need to use AWS IAM credentials with Amazon Cognito's identity pools. Amplify CLI can automatically configure this for you when running `amplify add auth` and will also automatically use the authenticated user from user pools to federate with the identity pools to provide the AWS IAM credentials in the application. [See this for more information about the differences](https://aws.amazon.com/premiumsupport/knowledge-center/cognito-user-pools-identity-pools/). This allows you to have both user pool credentials for AWS AppSync and AWS IAM credentials for other AWS resources. You can learn more about Amplify Auth outlined in the [Accessing credentials section](~/lib/auth/access_credentials.md). For manual configuration, add the following snippet to your `amplifyconfiguration.json` file, under the `awsCognitoAuthPlugin`: + +```json +{ + ... + "awsCognitoAuthPlugin": { + "CognitoUserPool": { + "Default": { + "PoolId": "[POOL-ID]", + "AppClientId": "[APP-CLIENT-ID]", + "AppClientSecret": "[APP-CLIENT-SECRET]", + "Region": "[REGION]" + } + } + } +} +``` +and under the `awsAPIPlugin` +```json +{ + ... + "awsAPIPlugin": { + " + + +#### IAM + +Amazon Cognito identity pools allows you to use credentials from AWS IAM in a mobile application. The Amplify CLI can automatically configure this for you when running `amplify add auth`. For manual configuration, add the following snippet to your `amplifyconfiguration.json` file: + +```json +{ + ... + "awsCognitoAuthPlugin": { + "CredentialsProvider": { + "CognitoIdentity": { + "Default": { + "PoolId": "[COGNITO-IDENTITY-POOLID]", + "Region": "[REGION]" + } + } + } + } +} +``` +and under the `awsAPIPlugin` +```json +{ + ... + "awsAPIPlugin": { + " + + + +#### Multi-Auth + +This section talks about the capability of AWS AppSync to configure multiple authorization modes for a single AWS AppSync endpoint and region. Follow the [AWS AppSync Multi-Auth](https://docs.aws.amazon.com/appsync/latest/devguide/security.html#using-additional-authorization-modes) to configure multiple authorization modes for your AWS AppSync endpoint. + +You can now configure a single GraphQL API to deliver private and public data. Private data requires authenticated access using authorization mechanisms such as IAM, Cognito User Pools, and OIDC. Public data does not require authenticated access and is delivered through authorization mechanisms such as API Keys. You can also configure a single GraphQL API to deliver private data using more than one authorization type. For example, you can configure your GraphQL API to authorize some schema fields using OIDC, while other schema fields through Cognito User Pools and/or IAM. + +As discussed in the above linked documentation, certain fields may be protected by different authorization types. This can lead the same query, mutation, or subscription to have different responses based on the authorization sent with the request; Therefore, it is recommended to use the different `friendly_name_` as the `apiName` parameter in the `Amplify.API` call to reference each authorization type. + +The following snippets highlight the new values in the `amplifyconfiguration.json` and the client code configurations. + +The `friendly_name` illustrated here is created from Amplify CLI prompt. There are 4 clients in this configuration that connect to the same API except that they use different `AuthMode`. + +```json +{ + "UserAgent": "aws-amplify-cli/2.0", + "Version": "1.0", + "api": { + "plugins": { + "awsAPIPlugin": { + "[FRIENDLY-NAME-API-WITH-API-KEY]": { + "endpointType": "GraphQL", + "endpoint": "[GRAPHQL-ENDPOINT]", + "region": "[REGION]", + "authorizationType": "API_KEY", + "apiKey": "[API_KEY]" + }, + "[FRIENDLY-NAME-API-WITH-IAM": { + "endpointType": "GraphQL", + "endpoint": "[GRAPHQL-ENDPOINT]", + "region": "[REGION]", + "authorizationType": "API_IAM", + }, + "[FRIENDLY-NAME-API-WITH-USER-POOLS]": { + "endpointType": "GraphQL", + "endpoint": "https://xyz.appsync-api.us-west-2.amazonaws.com/graphql", + "region": "[REGION]", + "authorizationType": "AMAZON_COGNITO_USER_POOLS", + }, + "[FRIENDLY-NAME-API-WITH-OPENID-CONNECT]": { + "endpointType": "GraphQL", + "endpoint": "https://xyz.appsync-api.us-west-2.amazonaws.com/graphql", + "region": "[REGION]", + "authorizationType": "OPENID_CONNECT", + } + } + } + } +} +``` + +The `GRAPHQL-ENDPOINT` from AWS AppSync will look similar to `https://xyz.appsync-api.us-west-2.amazonaws.com/graphql`. + + + diff --git a/docs/lib/predictions/fragments/ios/getting-started/30_installLib.md b/docs/lib/predictions/fragments/ios/getting-started/30_installLib.md index ba3b332ea23..218db17d434 100644 --- a/docs/lib/predictions/fragments/ios/getting-started/30_installLib.md +++ b/docs/lib/predictions/fragments/ios/getting-started/30_installLib.md @@ -4,6 +4,7 @@ To install the libraries required to translating text, **add both `AWSPrediction target 'MyAmplifyApp' do use_frameworks! pod 'Amplify' + pod 'AmplifyPlugins/AWSCognitoAuthPlugin' pod 'AWSPredictionsPlugin' pod 'CoreMLPredictionsPlugin' end diff --git a/docs/lib/predictions/fragments/ios/getting-started/40_init.md b/docs/lib/predictions/fragments/ios/getting-started/40_init.md index 734e480b733..3489e6f4d85 100644 --- a/docs/lib/predictions/fragments/ios/getting-started/40_init.md +++ b/docs/lib/predictions/fragments/ios/getting-started/40_init.md @@ -1,29 +1,21 @@ To initialize the Amplify Predictions and Authentication categories, we are required to use the `Amplify.add()` method for each category we want. When we are done calling `add()` on each category, we finish configuring Amplify by calling `Amplify.configure()`. **Add the following imports** to the top of your `AppDelegate.swift` file: - ```swift import Amplify -import AWSMobileClient +import AmplifyPlugins import AWSPredictionsPlugin + ``` **Add the following code** to your AppDelegate's `application:didFinishLaunchingWithOptions` method: - ```swift func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - AWSMobileClient.default().initialize { (userState, error) in - guard error == nil else { - print("Error initializing AWSMobileClient. Error: \(error!.localizedDescription)") - return - } - print("AWSMobileClient initialized, userstate: \(userState)") - } - do { + try Amplify.add(plugin: AWSCognitoAuthPlugin()) try Amplify.add(plugin: AWSPredictionsPlugin()) try Amplify.configure() - print("Amplify initialized") + print("Amplify configured with Auth and Predictions plugins") } catch { print("Failed to initialize Amplify with \(error)") } diff --git a/docs/lib/predictions/fragments/ios/getting-started/50_translate.md b/docs/lib/predictions/fragments/ios/getting-started/50_translate.md index edc01cb489c..10e01e20964 100644 --- a/docs/lib/predictions/fragments/ios/getting-started/50_translate.md +++ b/docs/lib/predictions/fragments/ios/getting-started/50_translate.md @@ -1,19 +1,15 @@ ```swift -import Amplify - -... - -func translateText(text:String) { +func translateText() { _ = Amplify.Predictions.convert(textToTranslate: "I like to eat spaghetti", language: .english, targetLanguage: .spanish, options: PredictionsTranslateTextRequest.Options(), listener: { (event) in switch event { - case .completed(let result): + case .success(let result): print(result.text) - default: - print("") + case .failure(let error): + print("Error: \(error)") } }) } diff --git a/docs/lib/push-notifications/fragments/js/getting-started.md b/docs/lib/push-notifications/fragments/js/getting-started.md index 7a12f3919ca..d5e2c7f79c6 100644 --- a/docs/lib/push-notifications/fragments/js/getting-started.md +++ b/docs/lib/push-notifications/fragments/js/getting-started.md @@ -16,27 +16,16 @@ Push Notifications category is integrated with [AWS Amplify Analytics category]( 2. Get your push messaging credentials for Android in Firebase console. [Click here for instructions](~/sdk/push-notifications/setup-push-service.md/q/platform/android). -3. Create a native link on a React Native app: +3. Install dependencies: ```bash - react-native init myapp - cd myapp - npm install aws-amplify && npm install @aws-amplify/pushnotification - react-native link @aws-amplify/pushnotification - react-native link amazon-cognito-identity-js # link if you need to Sign in into Cognito user pool + npm install aws-amplify @aws-amplify/pushnotification ``` - That would install required npm modules and link React Native binaries. - - Please note that linking `aws-amplify-react-native` but not completing the rest of the configuration steps could break your build process. Please be sure that you have completed all the steps before you build your app. - -4. Add your push messaging credentials (API key and Sender ID) with Amplify CLI by using the following commands: +4. Add your push messaging credentials (Server key) with Amplify CLI by using the following commands: ```bash - cd myapp - amplify init amplify add notifications - amplify push ``` Choose *FCM* when promoted: @@ -73,33 +62,17 @@ Push Notifications category is integrated with [AWS Amplify Analytics category]( 6. Open *android/build.gradle* file and perform following edits: - - Add *classpath 'com.google.gms:google-services:3.2.0'* in the `dependencies` under *buildscript*: + - Add `classpath("com.google.gms:google-services:4.3.3")` in the `dependencies` under `buildscript`: ```gradle + buildscript { + ... dependencies { - classpath 'com.android.tools.build:gradle:2.2.3' - classpath 'com.google.gms:google-services:3.2.0' - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } - ``` - Also update maven `url` as the following under *allprojects > repositories*. Revise *allprojects* to be: - - ```gradle - allprojects { - repositories { - mavenLocal() - jcenter() - maven { - // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm - url "$rootDir/../node_modules/react-native/android" - } - maven { - url "https://maven.google.com" - } - } + ... + classpath("com.google.gms:google-services:4.3.3") + ... } + } ``` 7. Open *android/app/build.gradle* and perform following edits: @@ -108,21 +81,25 @@ Push Notifications category is integrated with [AWS Amplify Analytics category]( ```gradle dependencies { - compile project(':@aws-amplify/pushnotification') - .. - .. - .. - compile 'com.google.firebase:firebase-core:12.0.1' - compile 'com.google.firebase:firebase-messaging:12.0.1' + ... + implementation "com.google.firebase:firebase-core:12.0.1" + implementation "com.google.firebase:firebase-messaging:12.0.1" + ... } ``` - Add following configuration to the bottom of the file: ```gradle - apply plugin: 'com.google.gms.google-services' + apply plugin: "com.google.gms.google-services" ``` -8. Open *android/app/src/main/AndroidManifest.xml* file and add the following configuration into `application` element. +8. Open *android/gradle/wrapper/gradle-wrapper.properties* update the Gradle `distributionUrl`: + + ```properties + distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip + ``` + +9. Open *android/app/src/main/AndroidManifest.xml* file and add the following configuration into `application` element. ```xml @@ -155,12 +132,12 @@ Push Notifications category is integrated with [AWS Amplify Analytics category]( ``` -9. Configure Push Notifications category for your app as shown in [Configure your App](#configure-your-app) section. +10. Configure Push Notifications category for your app as shown in [Configure your App](#configure-your-app) section. -10. Run your app with `yarn` or with an appropriate run command. +11. Run your app: ```bash - npm start + npx react-native run-android ``` ## Setup for iOS @@ -169,25 +146,19 @@ Push Notifications category is integrated with [AWS Amplify Analytics category]( 2. Setup iOS Push Notifications and create a p12 certificate as instructed here in [Amazon Pinpoint Developer Guide](https://docs.aws.amazon.com/pinpoint/latest/developerguide/apns-setup.html). -3. Create a native link on a React Native app: +3. Install dependencies and CocoaPods: ```bash - react-native init myapp - cd myapp - npm install - npm install aws-amplify \ - @aws-amplify/pushnotification \ - @react-native-community/push-notification-ios - cd ios && pod install + npm install aws-amplify @aws-amplify/pushnotification @react-native-community/push-notification-ios + ``` + ```bash + npx pod-install ``` 4. Enable notifications and add your p12 certificate with Amplify CLI by using the following commands: ```bash - cd myapp - amplify init amplify add notifications - amplify push ``` Choose *APNS* when promoted: @@ -200,31 +171,32 @@ Push Notifications category is integrated with [AWS Amplify Analytics category]( SMS ``` + Choose *Certificate* when promoted: + + ```console + ? Choose authentication method used for APNs + > Certificate + Key + ``` + The CLI will prompt for your *p12 certificate path*, enter it respectively. -5. Setup Xcode for push notification support by following the "Add Capabilities : Background Mode - Remote Notifications" and "Augment AppDelegate" sections found in the: [React Native Push Notifications Documentation](https://github.com/react-native-community/push-notification-ios) +5. Open project in Xcode and make updates for `@react-native-community/push-notification-ios`: + - [Add Capabilities : Background Mode - Remote Notifications](https://github.com/react-native-community/push-notification-ios#add-capabilities--background-mode---remote-notifications) + - [Augment `AppDelegate`](https://github.com/react-native-community/push-notification-ios#augment-appdelegate) 6. Update General App settings: - - Make sure you have logged in with your Apple Developer account on Xcode - Set bundle identifier (with the one you create on your Apple Developer Account) - - Unselect **Automatically manage signing** under **Signing** section - - On Signing (Debug, Release) set the provisioning profile (created on your Apple Developer Account) - - *Following screencast shows the required app settings in Xcode:* - + - Make sure you have logged in with your Apple Developer account on Xcode and have a Team selected for the target. 7. Configure Push Notification module for your app as shown in [Configure your App](#configure-your-app) section. -8. Run your app: +8. Run your app: - - On Xcode, select your device and run it first using as *Executable appName.app*. This will install the App on your device but it won't run it. - - Select **Ask on Launch** for *Executable* option on menu chain *Product > Schema > Edit Scheme > Run > Info*. - - Click *Run* button and select your app from the list. - - In case the build fails, try cleaning the project with *shift + command + k*. - - *Following screencast shows the required app settings in Xcode:* - + ```bash + npx react-native run-ios --device + ``` ## Configure your App @@ -236,36 +208,35 @@ If you don't have Analytics already enabled, see our [Analytics Developer Guide] -First, import `PushNotification` module and configure it with `PushNotification.configure()`. - ```javascript -import { PushNotificationIOS } from '@react-native-community/push-notification-ios'; -import Analytics from '@aws-amplify/analytics'; +import Amplify from 'aws-amplify'; import PushNotification from '@aws-amplify/pushnotification'; +import { PushNotificationIOS } from '@react-native-community/push-notification-ios'; +import awsconfig from './aws-exports'; -// PushNotification need to work with Analytics -Analytics.configure({ - // You configuration will come here... -}); - -PushNotification.configure({ - appId: 'XXXXXXXXXXabcdefghij1234567890ab', - requestIOSPermissions: false, // OPTIONAL, defaults to true -}); +Amplify.configure(awsconfig); ``` -`requestIOSPermissions` is an optional boolean flag which specifies whether or not to automatically request push notifications permissions in iOS when calling `PushNotification.configure` for the first time. If not provided, it defaults to `true`. When set to `false`, you may later call the method `PushNotification.requestIOSPermissions` at the explicit point in your application flow when you want to prompt the user for permissions. +### Configuration Options -You can also use `aws-exports.js` file in case you have set up your backend with Amplify CLI. +- `requestIOSPermissions` is an optional boolean flag which specifies whether or not to automatically request push notifications permissions in iOS when calling `PushNotification.configure` for the first time. If not provided, it defaults to `true`. When set to `false`, you may later call the method `PushNotification.requestIOSPermissions` at the explicit point in your application flow when you want to prompt the user for permissions. +- `appId` is optional and *only* needed if `aws-exports` doesn't contain `aws_mobile_analytics_app_id` or you are manually configuring each category inside `Amplify.configure()`. ```javascript -import { PushNotificationIOS } from '@react-native-community/push-notification-ios'; -import Analytics from '@aws-amplify/analytics'; -import PushNotification from '@aws-amplify/pushnotification'; -import awsconfig from './aws-exports'; - -// PushNotification need to work with Analytics -Analytics.configure(awsconfig); - -PushNotification.configure(awsconfig); +Amplify.configure({ + ...awsconfig, + PushNotification: { + requestIOSPermissions: false + } +}); +``` +```javascript +Amplify.configure({ + Auth: { /* ... */ }, + Analytics: { /* ... */ }, + PushNotification: { + appId: 'XXXXXXXXXXabcdefghij1234567890ab', + requestIOSPermissions: false + } +}); ``` diff --git a/docs/lib/push-notifications/fragments/js/overview.md b/docs/lib/push-notifications/fragments/js/overview.md index 81accc7ac16..c57cb11884c 100644 --- a/docs/lib/push-notifications/fragments/js/overview.md +++ b/docs/lib/push-notifications/fragments/js/overview.md @@ -1,4 +1,4 @@ -The Push Notifications category allows you to integrate push notifications in your app with Amazon Pinpoint targeting and campaign management support. +The Push Notifications category allows you to integrate push notifications in your app with Amazon Pinpoint targeting, campaign, and journey management support. @@ -6,7 +6,7 @@ Push Notifications are currently supported only for **React Native**. For handli -This guide provides step-by-step instructions to start working with push notifications in React Native with Amazon Pinpoint. Amazon Pinpoint helps you to monitor your app's usage, create messaging campaigns targeted to specific user segments or demographics, and collect interaction metrics with push notifications. +This guide provides step-by-step instructions to start working with push notifications in React Native with Amazon Pinpoint. Amazon Pinpoint helps you to monitor your app's usage, create messaging campaigns and journeys targeted to specific user segments or demographics, and collect interaction metrics with push notifications. > Ensure you have [installed and configured the Amplify CLI and library](~/cli/start/install.md). diff --git a/docs/lib/push-notifications/fragments/js/working-with-api.md b/docs/lib/push-notifications/fragments/js/working-with-api.md index 28bdb33e8d9..91e2346e3f2 100644 --- a/docs/lib/push-notifications/fragments/js/working-with-api.md +++ b/docs/lib/push-notifications/fragments/js/working-with-api.md @@ -6,7 +6,7 @@ PushNotification.onNotification((notification) => { // Note that the notification object structure is different from Android and IOS console.log('in app notification', notification); - // required on iOS only (see fetchCompletionHandler docs: https://facebook.github.io/react-native/docs/pushnotificationios.html) + // required on iOS only (see fetchCompletionHandler docs: https://github.com/react-native-community/push-notification-ios#finish) notification.finish(PushNotificationIOS.FetchResult.NoData); }); diff --git a/docs/lib/restapi/fragments/js/fetch.md b/docs/lib/restapi/fragments/js/fetch.md index 506a3376c97..8a408b9ffd4 100644 --- a/docs/lib/restapi/fragments/js/fetch.md +++ b/docs/lib/restapi/fragments/js/fetch.md @@ -26,17 +26,19 @@ API Example with async/await ```javascript -async getData() { +function getData() { const apiName = 'MyApiName'; const path = '/path'; const myInit = { // OPTIONAL headers: {}, // OPTIONAL }; - return await API.get(apiName, path, myInit); + return API.get(apiName, path, myInit); } -getData(); +(async function () { + const response = await getData(); +})(); ``` ## GET requests with query parameters @@ -70,17 +72,19 @@ API Example with async/await: ```javascript -async function head() { - const apiName = 'MyApiName'; - const path = '/path'; - const myInit = { // OPTIONAL - headers: {}, // OPTIONAL - }; - - return await API.head(apiName, path, myInit); +function head() { + const apiName = 'MyApiName'; + const path = '/path'; + const myInit = { // OPTIONAL + headers: {}, // OPTIONAL + }; + + return API.head(apiName, path, myInit); } -head(); +(async function () { + const response = await head(); +})(); ``` ## Accessing query parameters & body in Lambda proxy function diff --git a/docs/start/getting-started/add-api.md b/docs/start/getting-started/add-api.md new file mode 100644 index 00000000000..acec1365bc4 --- /dev/null +++ b/docs/start/getting-started/add-api.md @@ -0,0 +1,8 @@ +--- +title: Connect to the cloud +description: Getting Started with Amplify Libraries - how to add API and database to your app. +filterKey: integration +--- + + + diff --git a/docs/start/getting-started/fragments/android/native_add-api.md b/docs/start/getting-started/fragments/android/add-api.md similarity index 100% rename from docs/start/getting-started/fragments/android/native_add-api.md rename to docs/start/getting-started/fragments/android/add-api.md diff --git a/docs/start/getting-started/fragments/android/build-footer.md b/docs/start/getting-started/fragments/android/build-footer.md index 41d5a5c94df..0ee241676dc 100644 --- a/docs/start/getting-started/fragments/android/build-footer.md +++ b/docs/start/getting-started/fragments/android/build-footer.md @@ -1,4 +1,4 @@
- + Start the Tutorial � \ No newline at end of file diff --git a/docs/start/getting-started/fragments/android/native_generate-model.md b/docs/start/getting-started/fragments/android/generate-model.md similarity index 100% rename from docs/start/getting-started/fragments/android/native_generate-model.md rename to docs/start/getting-started/fragments/android/generate-model.md diff --git a/docs/start/getting-started/fragments/android/native_integrate.md b/docs/start/getting-started/fragments/android/integrate.md similarity index 100% rename from docs/start/getting-started/fragments/android/native_integrate.md rename to docs/start/getting-started/fragments/android/integrate.md diff --git a/docs/start/getting-started/fragments/android/nextsteps.md b/docs/start/getting-started/fragments/android/nextsteps.md new file mode 100644 index 00000000000..09b89dea1ee --- /dev/null +++ b/docs/start/getting-started/fragments/android/nextsteps.md @@ -0,0 +1,9 @@ +👏 In this tutorial, you created an application that persists data both locally on the device and in the cloud. You are now ready to start exploring additional Amplify categories to add to your application. + +- [Authentication](~/lib/auth/getting-started.md) +- [Storage](~/lib/storage/getting-started.md) +- [DataStore](~/lib/datastore/getting-started.md) +- [API (GraphQL)](~/lib/graphqlapi/getting-started.md) +- [API (REST)](~/lib/restapi/getting-started.md) +- [Analytics](~/lib/analytics/getting-started.md) +- [Predictions](~/lib/predictions/getting-started.md) \ No newline at end of file diff --git a/docs/start/getting-started/fragments/android/native_setup.md b/docs/start/getting-started/fragments/android/setup.md similarity index 100% rename from docs/start/getting-started/fragments/android/native_setup.md rename to docs/start/getting-started/fragments/android/setup.md diff --git a/docs/start/getting-started/fragments/angular/setup.md b/docs/start/getting-started/fragments/angular/setup.md index 4283b3387bc..1ac36a15bd1 100644 --- a/docs/start/getting-started/fragments/angular/setup.md +++ b/docs/start/getting-started/fragments/angular/setup.md @@ -31,10 +31,10 @@ Now that we have a running Angular app, it's time to set up Amplify for this app amplify init ``` -When you initialize Amplify you'll be prompted for some information about the app: +When you initialize Amplify you'll be prompted for some information about the app. For newer versions of Angular, you will have to change the Distribution Directory Path from `dist` to `dist/myAmplifyProject` to match how Angular will build your project. ```console -Enter a name for the project (photo-share) +Enter a name for the project (myAmplifyProject) # All AWS services you provision for your app are grouped into an "environment" # A common naming convention is dev, staging, and production @@ -51,6 +51,7 @@ What JavaScript framework are you using (angular) Source directory path (src) Distribution directory path (dist) +Change from dist to dist/myAmplifyProject Build command (npm run-script build) diff --git a/docs/start/getting-started/fragments/ios/native_add-api.md b/docs/start/getting-started/fragments/ios/add-api.md similarity index 100% rename from docs/start/getting-started/fragments/ios/native_add-api.md rename to docs/start/getting-started/fragments/ios/add-api.md diff --git a/docs/start/getting-started/fragments/ios/build-footer.md b/docs/start/getting-started/fragments/ios/build-footer.md index 41d5a5c94df..0ee241676dc 100644 --- a/docs/start/getting-started/fragments/ios/build-footer.md +++ b/docs/start/getting-started/fragments/ios/build-footer.md @@ -1,4 +1,4 @@
- + Start the Tutorial � \ No newline at end of file diff --git a/docs/start/getting-started/fragments/ios/native_generate-model.md b/docs/start/getting-started/fragments/ios/generate-model.md similarity index 100% rename from docs/start/getting-started/fragments/ios/native_generate-model.md rename to docs/start/getting-started/fragments/ios/generate-model.md diff --git a/docs/start/getting-started/fragments/ios/native_integrate.md b/docs/start/getting-started/fragments/ios/integrate.md similarity index 100% rename from docs/start/getting-started/fragments/ios/native_integrate.md rename to docs/start/getting-started/fragments/ios/integrate.md diff --git a/docs/start/getting-started/fragments/ios/nextsteps.md b/docs/start/getting-started/fragments/ios/nextsteps.md new file mode 100644 index 00000000000..09b89dea1ee --- /dev/null +++ b/docs/start/getting-started/fragments/ios/nextsteps.md @@ -0,0 +1,9 @@ +👏 In this tutorial, you created an application that persists data both locally on the device and in the cloud. You are now ready to start exploring additional Amplify categories to add to your application. + +- [Authentication](~/lib/auth/getting-started.md) +- [Storage](~/lib/storage/getting-started.md) +- [DataStore](~/lib/datastore/getting-started.md) +- [API (GraphQL)](~/lib/graphqlapi/getting-started.md) +- [API (REST)](~/lib/restapi/getting-started.md) +- [Analytics](~/lib/analytics/getting-started.md) +- [Predictions](~/lib/predictions/getting-started.md) \ No newline at end of file diff --git a/docs/start/getting-started/fragments/ios/native_setup.md b/docs/start/getting-started/fragments/ios/setup.md similarity index 100% rename from docs/start/getting-started/fragments/ios/native_setup.md rename to docs/start/getting-started/fragments/ios/setup.md diff --git a/docs/start/getting-started/fragments/vanillajs/hosting.md b/docs/start/getting-started/fragments/vanillajs/hosting.md index fd2fd99ba08..2eb5e094128 100644 --- a/docs/start/getting-started/fragments/vanillajs/hosting.md +++ b/docs/start/getting-started/fragments/vanillajs/hosting.md @@ -27,4 +27,6 @@ amplify publish After publishing, your terminal will display your app URL hosted on a `amplifyapp.com` domain. Whenever you have additional changes to publish, just re-run the `amplify publish` command. +If you get an "AccessDenied" error within an XML document, ensure that `DistributionDir` is set to the correct directory in `amplify/.config/project-config.json` and then re-run `amplify publish` + To view your app and hosting configuration in the Amplify Console, run the `amplify console` command. diff --git a/docs/start/getting-started/native_generate-model.md b/docs/start/getting-started/generate-model.md similarity index 67% rename from docs/start/getting-started/native_generate-model.md rename to docs/start/getting-started/generate-model.md index 91ef4305b6d..92d42fdb3f2 100644 --- a/docs/start/getting-started/native_generate-model.md +++ b/docs/start/getting-started/generate-model.md @@ -4,5 +4,5 @@ description: Getting Started with Amplify Libraries - Generate model files filterKey: integration --- - - + + diff --git a/docs/start/getting-started/native_integrate.md b/docs/start/getting-started/integrate.md similarity index 70% rename from docs/start/getting-started/native_integrate.md rename to docs/start/getting-started/integrate.md index 6291fe47915..fdbb7188fad 100644 --- a/docs/start/getting-started/native_integrate.md +++ b/docs/start/getting-started/integrate.md @@ -4,5 +4,5 @@ description: Getting Started with Amplify Libraries - How to integrate Amplify i filterKey: integration --- - - + + diff --git a/docs/start/getting-started/menu.json b/docs/start/getting-started/menu.json index 071b65d5cb8..e3c1c1229ad 100644 --- a/docs/start/getting-started/menu.json +++ b/docs/start/getting-started/menu.json @@ -6,10 +6,9 @@ "data-model", "auth", "hosting", - "nextsteps", - "native_setup", - "native_generate-model", - "native_integrate", - "native_add-api" + "generate-model", + "integrate", + "add-api", + "nextsteps" ] } \ No newline at end of file diff --git a/docs/start/getting-started/native_add-api.md b/docs/start/getting-started/native_add-api.md deleted file mode 100644 index 12f6524ec6f..00000000000 --- a/docs/start/getting-started/native_add-api.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -title: Connect to the cloud -description: Getting Started with Amplify Libraries - how to add API and database to your app. -filterKey: integration ---- - - - - -## Next steps - -In this tutorial, you created an application that persists data both locally on the device and in the cloud. You are now ready to start exploring additional Amplify categories to add to your application. - -- [Authentication](~/lib/auth/getting-started.md) -- [Storage](~/lib/storage/getting-started.md) -- [DataStore](~/lib/datastore/getting-started.md) -- [API (GraphQL)](~/lib/graphqlapi/getting-started.md) -- [API (REST)](~/lib/restapi/getting-started.md) -- [Analytics](~/lib/analytics/getting-started.md) -- [Predictions](~/lib/predictions/getting-started.md) diff --git a/docs/start/getting-started/native_setup.md b/docs/start/getting-started/native_setup.md deleted file mode 100644 index d7129105b97..00000000000 --- a/docs/start/getting-started/native_setup.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: Set up your project -description: Getting Started with Amplify Libraries - How to setup your project with Amplify -filterKey: integration ---- - - - diff --git a/docs/start/getting-started/nextsteps.md b/docs/start/getting-started/nextsteps.md index e20397d985a..d8ae6f464e4 100644 --- a/docs/start/getting-started/nextsteps.md +++ b/docs/start/getting-started/nextsteps.md @@ -14,4 +14,6 @@ description: Getting Started with Amplify Framework - Next steps - \ No newline at end of file + + + \ No newline at end of file diff --git a/docs/start/getting-started/setup.md b/docs/start/getting-started/setup.md index 9beac7ca127..46fd4f43ec4 100644 --- a/docs/start/getting-started/setup.md +++ b/docs/start/getting-started/setup.md @@ -8,4 +8,6 @@ description: Getting Started with Amplify Framework - Setup a fullstack project - \ No newline at end of file + + + \ No newline at end of file diff --git a/package.json b/package.json index 92745a84c8c..fba2b0b69b2 100644 --- a/package.json +++ b/package.json @@ -17,8 +17,7 @@ "@aws-amplify/ui-components": "^0.5.0", "array-flatten": "^3.0.0", "copy-to-clipboard": "^3.2.1", - "emotion": "^10.0.23", - "is-html-tag-name": "^1.0.2" + "emotion": "^10.0.23" }, "devDependencies": { "@stencil/core": "^1.13.0", diff --git a/tasks/build.ts b/tasks/build.ts index 3bcf4f61b9e..66757ed9706 100644 --- a/tasks/build.ts +++ b/tasks/build.ts @@ -2,7 +2,7 @@ import * as c from "capi/src"; import * as path from "path"; import {spawn} from "child_process"; import {filterOptionsByName} from "../client/src/utils/filter-data"; -import * as fs from "fs-extra"; +import * as fs from "fs"; const clientDir = path.join(__dirname, "../client"); @@ -26,10 +26,15 @@ const StencilBuildProcess = (flags: string[]) => }); const DEV_FLAGS = ["--dev", "--watch", "--serve"]; -const PROD_FLAGS = ["--prerender", "--debug"]; +const PROD_FLAGS = ["--prod", "--prerender", "--debug"]; -const onWatching = () => StencilBuildProcess(DEV_FLAGS); -const onTargetsWritten = () => StencilBuildProcess(PROD_FLAGS); +const onWatching = () => { + StencilBuildProcess(DEV_FLAGS); +}; + +const onTargetsWritten = () => { + StencilBuildProcess(PROD_FLAGS); +}; const watch = !!(process.argv[3] === "--watch"); const skipClientBuild = !!(process.argv[3] === "--skip-client-build"); diff --git a/yarn.lock b/yarn.lock index 18787784618..a6a7bdb3a33 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3640,11 +3640,6 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" -is-html-tag-name@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-html-tag-name/-/is-html-tag-name-1.0.2.tgz#31383fb8ed5a10a9a40a9b2604f001ff714cb42d" - integrity sha512-Uhb8WbabI/sI/uCUZasvjnxPj1tGyXOQdc9glOnsmsjbMOAmDBdhQbOaku20ekjODmkCF+Bp1wG68zsH2EvChA== - is-negated-glob@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-negated-glob/-/is-negated-glob-1.0.0.tgz#6910bca5da8c95e784b5751b976cf5a10fee36d2"