npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@advancedalgos/web-components

v0.0.18

Published

Shared web components for Advanced Algos modules

Downloads

55

Readme

Advanced Algos Web Components

npm version

Introduction

The is a repository for shared React web components between the Advanced Algos platform modules.

Installation

This is a Node.js module available through the npm registry. Installation is done using the npm install command:

$ npm install @advancedalgos/web-components

Usage

MessageCard

The Message Card is a simple component for outputting a message within a card. Great for using as a placeholder or adding simple formatting to error and loading messages.

import React from 'react'
import { MessageCard } from '@advancedalgos/web-components'

export const YourComponent = () => (
  <div>
    <MessageCard message='A message!' />
    <MessageCard message='That can also wrap other components' >
      <div className='loader'>Loading...</div>
    </MessageCard>
  </div>
)

Message Card Configuration Options

| Props | Type | Default | Note | | ------------------ | --------------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | message | String | --- | Display any string | | <children> | Node | --- | Can accept children nodes. |

Image Upload

Image Upload is a complex multi-functional component that encompasses allowing a user to preview an existing image, choose a new image, crop and resize that image, and then upload that image to Azure Blob Storage.

We use an Azure Shared Access Signature (SAS) created on a by-container basis that should be created on your server-side. The ImageUpload component then appends the SAS query parameters to the Storage Blob url with container and filename to upload the image.

View the Full Example for examples with use of client-side GraphQL mutation and server-side generation of the SASurl.

import React from 'react'
import { MessageCard, ImageUpload } from '@advancedalgos/web-components'

const YourComponent = ({ handleAvatar, filename, containerName, avatar, AzureStorageUrl, AzureSASURL }) => (
  <React.Fragment>
    <h1>Upload an image</h1>
    <ImageUpload
      handleUrl={handleAvatar}
      fileName={fileName}
      containerName={containerName}
      existingImage={avatar}
      imagePreviewConfig={{ width: 350, height:'auto', title: 'Change Avatar', fontSize: '1.5em' }}
      cropContainerConfig={{ x: 10, y: 10, width: 200, height: 200 }}
      cropPreviewBox={{ width: 350, height: 350 }}
      saveImageConfig={{
        quality: 0.6,
        maxWidth: 200,
        maxHeight: 200,
        autoRotate: true,
        mimeType: 'image/jpeg'
      }}
      containerStyle={{
        display: 'block',
        margin: '30px',
        height: '100px',
        width: '400px',
        overflow: 'visible'
      }}
      dropzoneStyle={{ height: 200 }}
      AzureStorageUrl={AzureStorageUrl}
      AzureSASURL={AzureSASURL}
      cropRatio={1}
    />
  </React.Fragment>
)

export default YourComponent

Image Upload Configuration Options

| Props | Type | Note | | ------------------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | | handleUrl | Function | Required. Receives the url of the uploaded image | | fileName | String | Required. File name that image is uploaded to storage as | | containerName | String | Required. StorageContainer name that image is uploaded to | | existingImage | String (url) | Url of pre-existing image. Usually will be same as URL returned from handleUrl | | imagePreviewConfig | Object | Existing image preview and change button text | | containerStyle | Object | Style of main container | | dropzoneStyle | Object | Style of dropzone container | | cropContainerConfig | Object | Size and location of cropper on image in crop mode | | cropPreviewBox | Object | Dimensions of cropper preview | | cropRatio | Number | ratio (width/height) image is cropped at eg. 1/1, 4/1, 16/9, 800/150 | | saveImageConfig | Object | Configuration of image saved to storage | | AzureStorageUrl | String | Required. Azure Storage Url (just the storage url; container and filename will be appended) | | AzureSASURL | String | Required. The Azure Shared Access Signature (SAS) that allows saving to the Blob without using full-access keys. See Full Example for server side example.

Image Upload Default Values

| Props | Default | | ------------------ | ------------- | | containerStyle | { display: 'block', margin: 0, height: 200, width: 200, overflow: 'visible' } | | dropzoneStyle | { height: 200 } | | imagePreviewConfig | { width: 350, height: auto, title: 'Change Avatar', fontSize: '24px' } | | cropContainerConfig | { x: 10, y: 10, width: 200, height: 200 } | |cropPreviewBox | { width: 350, height: 350 } | |cropRatio | 1 / 1 | |saveImageConfig | {quality: 0.6, maxWidth: 200, maxHeight: 200, autoRotate: true, debug: true, mimeType: 'image/jpeg} |

Image Upload Full Example

YourComponent.js

import React, { Component } from 'react'
import gql from 'graphql-tag'
import { MessageCard, ImageUpload } from '@advancedalgos/web-components'

const GET_AZURE_SAS = gql`
  mutation getAzureSAS($containerName: String!) {
    getAzureSAS(containerName: $containerName)
  }
`

export class YourComponent extends Component {
  constructor (props) {
    super(props)

    this.handleAvatar = this.handleAvatar.bind(this)

    this.state = {
      avatar: null
    }
  }

  render () {
    const { user, avatar } = this.props
    return (
      <Mutation mutation={UPDATE_USER_PROFILE} >
        {(updateUserProfile, { loading, error, data }) => {
        	let user = data.updateUserProfile
            if (loading) {
              loader = (<MessageCard message='Updating user profile...' />)
            }

          return (
              <Mutation mutation={GET_AZURE_SAS} >
                {(getAzureSAS, { loading, error, data }) => {

                  const AzureStorageUrl = process.env.AZURE_STORAGE_URL
                  const containerName = user.name
                  const fileName = `${user.name}-avatar.jpg`
                  let avatar = user.profile.avatar

                  let AzureSASURL
                  if (!loading && data !== undefined) {
                    AzureSASURL = data.getAzureSAS
                  } else {
                    getAzureSAS({ variables: { containerName: containerName } })
                  }

                  if (loading || data === undefined) {
                    return (<MessageCard message='Loading...' />)
                  } else {
                    return (
                      <React.Fragment>
                        <ImageUpload
                          handleUrl={this.handleAvatar}
                          fileName={fileName}
                          containerName={containerName}
                          existingImage={avatar}
                          imagePreviewConfig={{ width: 350, title: 'Change Avatar' }}
      					  cropContainerConfig={{ x: 10, y: 10, width: 200, height: 200 }}                          cropPreviewBox={{ width: 350, height: 350 }}
                          saveImageConfig={{
                            quality: 0.6,
                            maxWidth: 200,
                            maxHeight: 200,
                            autoRotate: true,
                            mimeType: 'image/jpeg'
                          }}
                          AzureStorageUrl={AzureStorageUrl}
                          AzureSASURL={AzureSASURL}
                          cropRatio={1}
                        />
                      </React.Fragment>
                    )
                  }
                }}
              </Mutation>      
    		)
        }}
      </Mutation>
    )
  }

  handleAvatar (avatarUrl) {
    console.log('handleAvatar: ', avatarUrl)
    this.setState({ avatar: `${avatarUrl}?${Math.random()}` })  // random number makes browser load latest image version
  }
}

ServerSide: server.js

const { createSASQueryURL } = require('./storage/azure')

...
const resolvers = {
	...
	Mutation: {
		async getAzureSAS(parent, { teamSlug }, ctx, info) {
	      const SASUrl = createSASQueryURL(teamSlug)
	      console.log('createSASQueryURL: ', SASUrl)
	      return SASUrl
	    }
    }
}

ServerSide: azure.js

const Azure = require("@azure/storage-blob")
const azureAccount = process.env.AZURE_STORAGE_ACCOUNT
const azureKey = process.env.AZURE_STORAGE_ACCESS_KEY
const azureStorageUrl = process.env.AZURE_STORAGE_URL

const createSASQueryURL = async (containerName) => {
  let today = new Date()
  let week = new Date()
  week.setDate(today.getDate() + 7)

  // Create SharedKeyCredential and attach to pipline
  const SKC = new Azure.SharedKeyCredential(azureAccount, azureKey)
  const pipeline = Azure.StorageURL.newPipeline(SKC)

  // Create container URL
  const serviceURL = new Azure.ServiceURL(azureStorageUrl, pipeline)
  const containerURL = Azure.ContainerURL.fromServiceURL(serviceURL, containerName)

  //list container and check if already exists.
  let marker
  let containerCheck = null
  do {
    const listContainersResponse = await serviceURL.listContainersSegment(
      Azure.Aborter.None,
      marker,
    )
    marker = listContainersResponse.marker;
    for (const container of listContainersResponse.containerItems) {

      if(container.name === containerName){
        containerCheck = container.name
      }
    }
  } while (marker)

  // if container doesn't exist, create one
  let newContainer
  if(containerCheck === null){
    newContainer = await containerURL.create(Azure.Aborter.None, { access: 'blob' })
  }

  // Set permissions for service, resource types and containers
  const SASContainerPerms = await Azure.AccountSASPermissions.parse('rwlacu')
  const SASServicePerms = await Azure.AccountSASServices.parse('b')
  const SASResourceTypes = await Azure.AccountSASResourceTypes.parse('co')

  // Generate SAS url
  const SASQueryParameters = await Azure.generateBlobSASQueryParameters(
    {
      version: '2017-11-09',
      protocol: 'https,http',
      expiryTime: week,
      permissions: 'rwlac',
      containerName: containerName
    }, SKC )

  return SASQueryParameters
}

module.exports = { createSASQueryURL }

Page

The Page component is a wrapper that uses React Helmet to inject page title, description and other metadata into the header to represent the current view.

Supports basic meta data as well as metadata for Twitter and Facebook

** Note 1:** View .env.sample for extra configuration variables that should be added to your environment variables.

** Note 2:** Uses react-router-dom withRouter HoC and requires being used with & components

import React from 'react'
import { Page, MessageCard } from '@advancedalgos/web-components'

export const YourComponent = () => (
  <Page
    title='Advanced Algos Development Platform'
    subtitile='A Platform View'
    description='This describes the current view of the Advanced Algos Development Platform'
  >
    <MessageCard message={text('Message', 'This message is wrapped by a page component. Check header source to see inserted metadata.')} />
  </Page>
)

Page Configuration Options

| Props | Type | Default | Note | | ------------------ | --------------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | title | String | --- | Title of site | | subtitle | String | --- | Title of current view | | description | String | --- | Description of current view | | twitter | String | --- | Twitter handle (eg. @advancedalgos) and enables Twitter card metadata | | facebook | Boolean | --- | Enables Facebook OpenGraph metadata | | image | string | --- | URL of image that represents current view | | <children> | Node | --- | Can accept children nodes.

Developing This Package

==================================

Libraries

Getting Started

$ npm install
$ npm run storybook

Testing

$ npm run test