Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Artsy Open #156

Merged
merged 2 commits into from May 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Expand Up @@ -11,6 +11,10 @@ Artsy CLI is published on npm, so installing is really easy:
$ npm install --global @artsy/cli
```

## [Docs]

- [Artsy Open Docs](docs/open.md)

## Releasing

The release process happens automatically on every PR merge thanks to [auto](https://github.com/intuit/auto). To ensure
Expand Down
55 changes: 55 additions & 0 deletions docs/open.md
@@ -0,0 +1,55 @@
# Artsy CLI Open

Open Artsy links with iOS, Android or the browser.

## Usage

**With an alias:**

```
artsy open artwork
```

opens https://www.artsy.net/artwork/banksy-love-rat-signed-16 on iOS

**With a path:**

```
artsy open /artwork/andy-warhol-watercolor-paint-kit-with-brushes-11
```

opens https://www.artsy.net/artwork/andy-warhol-watercolor-paint-kit-with-brushes-11 on iOS

**With a full URL:**

```
artsy open https://www.staging.artsy.net/artwork/andy-warhol-watercolor-paint-kit-with-brushes-11
```

opens https://www.staging.artsy.net/artwork/andy-warhol-watercolor-paint-kit-with-brushes-11 on iOS

**With flags:**

```
artsy open artwork -a -l
```

opens localhost:3000/artwork/banksy-love-rat-signed-16 on Android

**With custom variables:**

```
artsy open artist artistID:andy-warhol
```

opens https://www.artsy.net/artist/andy-warhol on Android

## Config

All aliases and defaults can be found [here](src/lib/open/data/config.json).

The config can be overriden by providing `~/.config/artsy-open.json`. Just copy the config from GitHub and modify it:

```
curl https://www.raw.githubusercontent.com/artsy/cli/master/src/lib/open/data/config.json > ~/.config/artsy-open.json
```
7 changes: 6 additions & 1 deletion package.json
Expand Up @@ -20,7 +20,9 @@
"apollo-client": "^2.6.10",
"apollo-link-http": "^1.5.17",
"cli-ux": "^5.3.1",
"colon-template": "^1.0.3",
"cross-fetch": "^3.0.6",
"dashify": "^2.0.0",
"dotenv": "^8.0.0",
"graphql": "^15.5.0",
"graphql-tag": "^2.11.0",
Expand All @@ -29,7 +31,8 @@
"node-fetch": "^2.6.0",
"querystring": "^0.2.0",
"rss-parser": "^3.11.0",
"tslib": "^2"
"tslib": "^2",
"uri-scheme": "^1.0.76"
},
"devDependencies": {
"@artsy/auto-config": "^1.0.1",
Expand All @@ -42,6 +45,7 @@
"@oclif/test": "^1",
"@oclif/tslint": "^3",
"@types/chai": "^4",
"@types/dashify": "^1.0.0",
"@types/mocha": "^8",
"@types/node": "^14",
"@types/node-fetch": "^2.5.0",
Expand All @@ -52,6 +56,7 @@
"nock": "^13.0.10",
"nyc": "^13",
"prettier": "^1.18.2",
"sinon": "^10.0.0",
"ts-node": "^9",
"tslint": "^5",
"tslint-config-prettier": "^1.18.0",
Expand Down
81 changes: 81 additions & 0 deletions src/commands/open.ts
@@ -0,0 +1,81 @@
import { flags } from "@oclif/command"
import Command from "../base"

import openPage from "../lib/open"
import config from "../lib/open/config"

export default class Open extends Command {
static description =
"Open Artsy links with the iOS/Android emulator or the browser"

static examples = [
`$ artsy open artwork
opens "https://www.artsy.net/artwork/banksy-love-rat-signed-16" on iOS`,
`$ artsy open artwork/andy-warhol-watercolor-paint-kit-with-brushes-11
opens "https://www.artsy.net/artwork/andy-warhol-watercolor-paint-kit-with-brushes-11" on iOS`,
`artsy open artist artistID:andy-warhol
Open "https://www.artsy.net/artist/andy-warhol" on iOS`,
`$ artsy open home -a
opens "https://www.artsy.net/" on Android`,
`$ artsy open about -l
opens "localhost/about" on iOS`,
`\nALL PAGES`,
Object.keys(config.pages).join(", "),
]

static flags = {
...Command.flags,
ios: flags.boolean({ char: "i" }),
android: flags.boolean({ char: "a" }),
web: flags.boolean({ char: "w" }),
production: flags.boolean({ char: "p" }),
staging: flags.boolean({ char: "s" }),
local: flags.boolean({ char: "l" }),
}

static args = [
{ name: "page", required: false, default: "/" },
{ name: "customVariables", required: false },
]

parsePlatform(): string | undefined {
const { flags } = this.parse(Open)

if (flags.ios) return "ios"
if (flags.android) return "android"
if (flags.web) return "web"
}

parseEnvironment(): string | undefined {
const { flags } = this.parse(Open)

if (flags.staging) return "staging"
if (flags.production) return "production"
if (flags.local) return "local"
}

parseCustomVariables(): object {
const {
args: { customVariables },
} = this.parse(Open)

if (!customVariables) return {}

return customVariables.split(",").reduce((acc: any, element: string) => {
const [key, value] = element.split(":")
acc[key] = value
return acc
}, {})
}

async run() {
const { args } = this.parse(Open)

openPage({
page: args.page as string,
platform: this.parsePlatform(),
environment: this.parseEnvironment(),
customVariables: this.parseCustomVariables(),
})
}
}
9 changes: 9 additions & 0 deletions src/config.ts
Expand Up @@ -5,6 +5,15 @@ export const Config = {
path: (): string => {
return `${os.homedir()}/.config/artsy`
},
readOpenConfig: (): any => {
try {
return JSON.parse(
fs.readFileSync(`${os.homedir()}/.config/artsy-open.json`)
)
} catch {
return {}
}
},
readToken: (): string => {
return fs.readFileSync(Config.path(), { encoding: "utf-8" })
},
Expand Down
13 changes: 13 additions & 0 deletions src/lib/open/config.ts
@@ -0,0 +1,13 @@
import { Config } from "../../config"
import { defaults, environments, pages, variables } from "./data/config.json"

const homeConfig = Config.readOpenConfig()

const config = {
environments: { ...environments, ...homeConfig.environments },
pages: { ...pages, ...homeConfig.pages },
variables: { ...variables, ...homeConfig.variables },
defaults: { ...defaults, ...homeConfig.defaults },
}

export default config
103 changes: 103 additions & 0 deletions src/lib/open/data/config.json
@@ -0,0 +1,103 @@
{
"defaults": {
"environment": "production",
"platform": "ios"
},
"environments": {
"local": "localhost:3000",
"production": "https://www.artsy.net",
"staging": "https://www.staging.artsy.net"
},
"pages": {
"about": "/about",
"admin": "/admin",
"admin2": "/admin2",
"artist": "/artist/:artistID",
"artist-articles": "/artist/:artistID/articles",
"artist-series": "/artist-series/:artistSeriesID",
"artwork": "/artwork/:artworkID",
"artwork-attribution-class-faq": "/artwork-classifications",
"artwork-medium": "/artwork/:artworkID/medium",
"auction": "/auction/:auctionID",
"auction-bid-artwork": "/auction/:saleID/bid/:artworkID",
"auction-faq": "/auction-faq",
"auction-info": "/auction/:saleID/info",
"auction-registration": "/auction-registration/:saleID",
"auction-result": "/artist/:artistID/auction-result/:auctionResultInternalID",
"auction2": "/auction/:saleID",
"auctions": "/auctions",
"buy-now-feature-faq": "/buy-now-feature-faq",
"categories": "/categories",
"checkout": "/orders/:orderID",
"city-bmwlist": "/city-bmw-list/:citySlug",
"city-fair-list": "/city-fair/:citySlug",
"city-saved-list": "/city-save/:citySlug",
"city-section-list": "/city/:citySlug/:section",
"collection": "/collection/:collectionID",
"conditions-of-sale": "/conditions-of-sale",
"consignments-submission-form": "/consign/submission",
"conversation": "/user/conversations/:conversationID",
"fair": "/fair/:fairID/exhibitors",
"fair-all-followed-artists": "/fair/:fairID/followedArtists",
"fair-articles": "/fair/:fairID/articles",
"fair-bmwart-activation": "/fair/:fairID/bmw-sponsored-content",
"fair-more-info": "/fair/:fairID/info",
"favorites": "/favorites",
"feature": "/feature/:featureSlug",
"full-artist-series-list": "/artist/:artistID/artist-series",
"full-featured-artist-list": "/collection/:collectionID/artists",
"gene": "/gene/:geneID",
"home": "/",
"identity-verification-faq": "/identity-verification-faq",
"inbox": "/inbox",
"inquiry": "/inquiry/:artworkID",
"local-discovery": "/local-discovery",
"make-offer-modal": "/make-offer/:artworkID",
"my-account": "/my-account",
"my-account-edit-email": "/my-account/edit-email",
"my-account-edit-name": "/my-account/edit-name",
"my-account-edit-password": "/my-account/edit-password",
"my-account-edit-phone": "/my-account/edit-phone",
"my-collection": "/my-collection",
"my-collection-artwork": "/my-collection/artwork/:artworkSlug",
"my-collection-artwork-full-details": "/my-collection/artwork-details/:artworkSlug",
"my-collection-artwork-images": "/my-collection/artwork-images/:artworkSlug",
"my-profile": "/my-profile",
"my-profile-payment": "/my-profile/payment",
"my-profile-payment-new-credit-card": "/my-profile/payment/new-card",
"my-profile-push-notifications": "/my-profile/push-notifications",
"order": "/orders/:orderID",
"partner-locations": "/partner-locations/:partnerID",
"privacy": "/privacy",
"privacy-request": "/privacy-request",
"sales": "/sales",
"sales-not-root-tab-view": "/collections/my-collection/marketing-landing",
"search": "/search",
"show": "/show/:showID",
"show-more-info": "/show/:showID/info",
"terms": "/terms",
"viewing-room": "/viewing-room/:viewing_room_id",
"viewing-room-artwork": "/viewing-room/:viewing_room_id/:artworkID",
"viewing-room-artworks": "/viewing-room/:viewing_room_id/artworks",
"viewing-rooms": "/viewing-rooms",
"works-for-you": "/works-for-you"
},
"variables": {
"artistID": "banksy",
"artistSeriesID": "andy-warhol-watercolor-paint-kit-with-brushes",
"artworkID": "banksy-love-rat-signed-16",
"auctionID": "american-friends-of-museums-in-israel-benefit-auction-2021",
"auctionResultInternalID": "",
"citySlug": "berlin",
"collectionID": "abstract-expressionism-works-on-paper",
"conversationID": "",
"fairID": "one-x-artsy",
"featureSlug": "museum-of-contemporary-art-san-diego-benefit-auction-2020",
"geneID": "design",
"orderID": "",
"partnerID": "menconi-plus-schoelkopf",
"saleID": "american-friends-of-museums-in-israel-benefit-auction-2021",
"showID": "first-floor-gallery-harare-amanda-mushate-nguve-inemuridzi",
"viewing_room_id": "artcn-panacea-of-liu-zhenchen"
}
}
62 changes: 62 additions & 0 deletions src/lib/open/index.ts
@@ -0,0 +1,62 @@
const { Android, Ios } = require("uri-scheme")
const dashify = require("dashify")
const template = require("colon-template")
const { cli } = require("cli-ux")

import config from "./config"
interface OpenPageProps {
page: string
platform: string | undefined
environment: string | undefined
customVariables: object
}

const openUri = (uri: string, platform: string) => {
switch (platform) {
case "android":
Android.openAsync({ uri })
break
case "ios":
Ios.openAsync({ uri })
break
case "web":
cli.open(uri)
}
}

const removeTrailingSlash = (path: string): string => {
return path.replace(/^\//, "")
}

const getURI = (
input: string,
variables: object,
environment: string
): string => {
if (input.includes("://")) return input

const { pages, environments } = config

const templatePath = removeTrailingSlash(pages[dashify(input)] || input)

const path = template(templatePath, variables)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very cool! 💯


return `${environments[environment]}/${path}`
}

const openPage = ({
page,
platform,
environment,
customVariables,
}: OpenPageProps) => {
const variables = { ...config.variables, ...customVariables }
const env = environment || config.defaults.environment
const uri = getURI(page, variables, env)

console.log(`Open "${uri}" on ${platform || config.defaults.platform}`)

openUri(uri, platform || config.defaults.platform)
}

export default openPage