Skip to content

Commit

Permalink
Merge branch 'master' into put-object-options
Browse files Browse the repository at this point in the history
  • Loading branch information
drernie authored Nov 19, 2024
2 parents 4c8436f + 2eb3cfc commit 6cf089e
Show file tree
Hide file tree
Showing 47 changed files with 2,241 additions and 1,498 deletions.
2 changes: 2 additions & 0 deletions catalog/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ where verb is one of

## Changes

- [Fixed] Fix some doc URLs in catalog ([#4205](https://github.com/quiltdata/quilt/pull/4205))
- [Changed] S3 Select -> GQL API calls for getting access counts ([#4218](https://github.com/quiltdata/quilt/pull/4218))
- [Changed] Athena: improve loading state and errors visuals; fix minor bugs; alphabetize and persist selection in workgroups, catalog names and databases ([#4208](https://github.com/quiltdata/quilt/pull/4208))
- [Changed] Show stack release version in footer ([#4200](https://github.com/quiltdata/quilt/pull/4200))
- [Added] Selective package downloading ([#4173](https://github.com/quiltdata/quilt/pull/4173))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ function Header() {
return (
<M.Typography variant="body2">
Configuration for Catalog UI: show and hide features, set default values. See{' '}
<StyledLink href={`${docs}/catalog/preferences`} target="_blank">
<StyledLink
href={`${docs}/quilt-platform-administrator/preferences`}
target="_blank"
>
the docs
</StyledLink>
</M.Typography>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ function Header() {
return (
<M.Typography variant="body2">
Configuration for data quality workflows. See{' '}
<StyledLink href={`${docs}/advanced/workflows`} target="_blank">
<StyledLink href={`${docs}/workflows`} target="_blank">
the docs
</StyledLink>
</M.Typography>
Expand Down
5 changes: 4 additions & 1 deletion catalog/app/containers/Admin/Status/Status.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ export default function Status() {
GxP and other compliance regimes.
</M.Typography>
<M.Typography align="center">
<StyledLink href={`${docs}/advanced/good-practice`} target="_blank">
<StyledLink
href={`${docs}/quilt-platform-administrator/best-practices/good-practice`}
target="_blank"
>
Learn more
</StyledLink>{' '}
or <StyledLink href="mailto:[email protected]">contact sales</StyledLink>.
Expand Down
5 changes: 4 additions & 1 deletion catalog/app/containers/Admin/UsersAndRoles/SsoConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,10 @@ function Form({
<FormError error={error || submitError} errors={FORM_ERRORS} />
<M.Typography variant="body2">
Learn more about{' '}
<StyledLink href={`${docs}/advanced/sso-permissions`} target="_blank">
<StyledLink
href={`${docs}/quilt-platform-administrator/advanced/sso-permissions`}
target="_blank"
>
SSO permissions mapping
</StyledLink>
.
Expand Down
4 changes: 2 additions & 2 deletions catalog/app/containers/Bucket/CodeSamples/Dir.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ const TEMPLATES = {
dedent`
import quilt3 as q3
b = q3.Bucket("s3://${bucket}")
# List files [[${docs}/api-reference/bucket#bucket.ls]]
# List files [[${docs}/quilt-python-sdk-developers/api-reference/bucket#bucket.ls]]
b.ls("${path}")
# Download [[${docs}/api-reference/bucket#bucket.fetch]]
# Download [[${docs}/quilt-python-sdk-developers/api-reference/bucket#bucket.fetch]]
b.fetch("${path}", "./${dest}")
`,
CLI: (bucket: string, path: string, dest: string) =>
Expand Down
2 changes: 1 addition & 1 deletion catalog/app/containers/Bucket/CodeSamples/File.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const TEMPLATES = {
dedent`
import quilt3 as q3
b = q3.Bucket("s3://${bucket}")
# Download [[${docs}/api-reference/bucket#bucket.fetch]]
# Download [[${docs}/quilt-python-sdk-developers/api-reference/bucket#bucket.fetch]]
b.fetch("${path}", "./${basename(path)}")
`,
CLI: (bucket: string, path: string) =>
Expand Down
14 changes: 7 additions & 7 deletions catalog/app/containers/Bucket/CodeSamples/Package.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,30 @@ const TEMPLATES = {
const hashPy = hashDisplay && `, top_hash="${hashDisplay}"`
return dedent`
import quilt3 as q3
# Browse [[${docs}/api-reference/package#package.browse]]
# Browse [[${docs}/quilt-python-sdk-developers/api-reference/package#package.browse]]
p = q3.Package.browse("${name}"${hashPy}, registry="s3://${bucket}")
# make changes to package adding individual files [[${docs}/api-reference/package#package.set]]
# make changes to package adding individual files [[${docs}/quilt-python-sdk-developers/api-reference/package#package.set]]
p.set("data.csv", "data.csv")
# or whole directories [[${docs}/api-reference/package#package.set_dir]]
# or whole directories [[${docs}/quilt-python-sdk-developers/api-reference/package#package.set_dir]]
p.set_dir("subdir", "subdir")
# and push changes [[${docs}/api-reference/package#package.push]]
# and push changes [[${docs}/quilt-python-sdk-developers/api-reference/package#package.push]]
p.push("${name}", registry="s3://${bucket}", message="Hello World")
# Download (be mindful of large packages) [[${docs}/api-reference/package#package.push]]
# Download (be mindful of large packages) [[${docs}/quilt-python-sdk-developers/api-reference/package#package.install]]
q3.Package.install("${name}"${pathPy}${hashPy}, registry="s3://${bucket}", dest=".")
`
},
CLI_DOWNLOAD: (bucket: string, name: string, path: string, hashDisplay: string) => {
const pathCli = path && ` --path "${s3paths.ensureNoSlash(path)}"`
const hashCli = hashDisplay && ` --top-hash ${hashDisplay}`
return dedent`
# Download package [[${docs}/api-reference/cli#install]]
# Download package [[${docs}/quilt-python-sdk-developers/api-reference/cli#install]]
quilt3 install "${name}"${pathCli}${hashCli} --registry s3://${bucket} --dest .
`
},
CLI_UPLOAD: (bucket: string, name: string) =>
dedent`
# Upload package [[${docs}/api-reference/cli#push]]
# Upload package [[${docs}/quilt-python-sdk-developers/api-reference/cli#push]]
echo "Hello World" > README.md
quilt3 push "${name}" --registry s3://${bucket} --dir .
`,
Expand Down
92 changes: 92 additions & 0 deletions catalog/app/containers/Bucket/File/Analytics.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import * as dateFns from 'date-fns'
import * as Eff from 'effect'
import * as React from 'react'
import * as M from '@material-ui/core'

import Sparkline from 'components/Sparkline'
import * as GQL from 'utils/GraphQL'
import log from 'utils/Logging'
import * as SVG from 'utils/SVG'
import { readableQuantity } from 'utils/string'

import Section from '../Section'

import ACCESS_COUNTS_QUERY from './gql/ObjectAccessCounts.generated'

const currentYear = new Date().getFullYear()

const formatDate = (date: Date) =>
dateFns.format(date, currentYear === date.getFullYear() ? 'd MMM' : 'd MMM yyyy')

interface AnalyticsProps {
bucket: string
path: string
}

export default function Analytics({ bucket, path }: AnalyticsProps) {
const [cursor, setCursor] = React.useState<number | null>(null)

const result = GQL.useQuery(ACCESS_COUNTS_QUERY, { bucket, key: path })

const data = React.useMemo(() => {
if (result.fetching) return Eff.Option.none()
if (result.error) log.error('Error fetching object access counts:', result.error)
return Eff.Option.some(Eff.Option.fromNullable(result.data?.objectAccessCounts))
}, [result.fetching, result.error, result.data])

const defaultExpanded = Eff.Option.match(data, {
onNone: () => false,
onSome: Eff.Option.match({
onNone: () => false,
onSome: ({ total }) => !!total,
}),
})

return (
<Section icon="bar_charts" heading="Analytics" defaultExpanded={defaultExpanded}>
{Eff.Option.match(data, {
onNone: () => <M.CircularProgress />,
onSome: Eff.Option.match({
onNone: () => <M.Typography>No analytics available</M.Typography>,
onSome: ({ counts, total }) =>
total ? (
<M.Box
display="flex"
width="100%"
justifyContent="space-between"
alignItems="center"
>
<M.Box>
<M.Typography variant="h5">Downloads</M.Typography>
<M.Typography variant="h4" component="div">
{readableQuantity(cursor === null ? total : counts[cursor].value)}
</M.Typography>
<M.Typography variant="overline" component="span">
{cursor === null
? `${counts.length} days`
: formatDate(counts[cursor].date)}
</M.Typography>
</M.Box>
<M.Box width="calc(100% - 7rem)">
<Sparkline
data={counts.map((c) => c.value)}
onCursor={setCursor}
width={1000}
height={60}
stroke={SVG.Paint.Server(
<linearGradient x2="0" y2="100%" gradientUnits="userSpaceOnUse">
<stop offset="0" stopColor={M.colors.blueGrey[800]} />
<stop offset="100%" stopColor={M.colors.blueGrey[100]} />
</linearGradient>,
)}
/>
</M.Box>
</M.Box>
) : (
<M.Typography>No analytics available</M.Typography>
),
}),
})}
</Section>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as React from 'react'
import * as Assistant from 'components/Assistant'
import * as XML from 'utils/XML'

import { ObjectExistence } from './requests'
import { ObjectExistence } from '../requests'

interface VersionsContextProps {
data: $TSFixMe
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { basename } from 'path'

import * as dateFns from 'date-fns'
import * as R from 'ramda'
import * as React from 'react'
import { Link, useHistory, useLocation, useParams } from 'react-router-dom'
Expand All @@ -11,7 +10,6 @@ import * as Buttons from 'components/Buttons'
import * as FileEditor from 'components/FileEditor'
import Message from 'components/Message'
import * as Preview from 'components/Preview'
import Sparkline from 'components/Sparkline'
import cfg from 'constants/config'
import * as Bookmarks from 'containers/Bookmarks'
import * as Notifications from 'containers/Notifications'
Expand All @@ -21,23 +19,24 @@ import * as BucketPreferences from 'utils/BucketPreferences'
import { useData } from 'utils/Data'
import MetaTitle from 'utils/MetaTitle'
import * as NamedRoutes from 'utils/NamedRoutes'
import * as SVG from 'utils/SVG'
import { linkStyle } from 'utils/StyledLink'
import copyToClipboard from 'utils/clipboard'
import * as Format from 'utils/format'
import parseSearch from 'utils/parseSearch'
import { up, decode, handleToHttpsUri } from 'utils/s3paths'
import { readableBytes, readableQuantity } from 'utils/string'

import AssistButton from './AssistButton'
import FileCodeSamples from './CodeSamples/File'
import * as AssistantContext from './FileAssistantContext'
import FileProperties from './FileProperties'
import * as FileView from './FileView'
import Section from './Section'
import renderPreview from './renderPreview'
import * as requests from './requests'
import { useViewModes, viewModeToSelectOption } from './viewModes'
import { readableBytes } from 'utils/string'

import AssistButton from '../AssistButton'
import FileCodeSamples from '../CodeSamples/File'
import FileProperties from '../FileProperties'
import * as FileView from '../FileView'
import Section from '../Section'
import renderPreview from '../renderPreview'
import * as requests from '../requests'
import { useViewModes, viewModeToSelectOption } from '../viewModes'

import Analytics from './Analytics'
import * as AssistantContext from './AssistantContext'

const useVersionInfoStyles = M.makeStyles(({ typography }) => ({
version: {
Expand Down Expand Up @@ -203,69 +202,6 @@ function VersionInfo({ bucket, path, version }) {
)
}

function Analytics({ bucket, path }) {
const [cursor, setCursor] = React.useState(null)
const s3 = AWS.S3.use()
const today = React.useMemo(() => new Date(), [])
const formatDate = (date) =>
dateFns.format(
date,
today.getFullYear() === date.getFullYear() ? 'd MMM' : 'd MMM yyyy',
)
const data = useData(requests.objectAccessCounts, { s3, bucket, path, today })

const defaultExpanded = data.case({
Ok: ({ total }) => !!total,
_: () => false,
})

return (
<Section icon="bar_charts" heading="Analytics" defaultExpanded={defaultExpanded}>
{data.case({
Ok: ({ counts, total }) =>
total ? (
<M.Box
display="flex"
width="100%"
justifyContent="space-between"
alignItems="center"
>
<M.Box>
<M.Typography variant="h5">Downloads</M.Typography>
<M.Typography variant="h4" component="div">
{readableQuantity(cursor === null ? total : counts[cursor].value)}
</M.Typography>
<M.Typography variant="overline" component="span">
{cursor === null
? `${counts.length} days`
: formatDate(counts[cursor].date)}
</M.Typography>
</M.Box>
<M.Box width="calc(100% - 7rem)">
<Sparkline
data={R.pluck('value', counts)}
onCursor={setCursor}
width={1000}
height={60}
stroke={SVG.Paint.Server(
<linearGradient x2="0" y2="100%" gradientUnits="userSpaceOnUse">
<stop offset="0" stopColor={M.colors.blueGrey[800]} />
<stop offset="100%" stopColor={M.colors.blueGrey[100]} />
</linearGradient>,
)}
/>
</M.Box>
</M.Box>
) : (
<M.Typography>No analytics available</M.Typography>
),
Err: () => <M.Typography>No analytics available</M.Typography>,
_: () => <M.CircularProgress />,
})}
</Section>
)
}

function CenteredProgress() {
return (
<M.Box textAlign="center" width="100%">
Expand Down
Loading

0 comments on commit 6cf089e

Please sign in to comment.