diff options
Diffstat (limited to 'app/assets/javascripts/packages_and_registries')
13 files changed, 1103 insertions, 0 deletions
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/additional_metadata.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/additional_metadata.vue new file mode 100644 index 00000000000..89add0a0d31 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/additional_metadata.vue @@ -0,0 +1,94 @@ +<script> +import { GlLink, GlSprintf } from '@gitlab/ui'; +import { s__ } from '~/locale'; +import { PackageType } from '~/packages/shared/constants'; +import DetailsRow from '~/vue_shared/components/registry/details_row.vue'; + +export default { + i18n: { + sourceText: s__('PackageRegistry|Source project located at %{link}'), + licenseText: s__('PackageRegistry|License information located at %{link}'), + recipeText: s__('PackageRegistry|Recipe: %{recipe}'), + appGroup: s__('PackageRegistry|App group: %{group}'), + appName: s__('PackageRegistry|App name: %{name}'), + }, + components: { + DetailsRow, + GlLink, + GlSprintf, + }, + props: { + packageEntity: { + type: Object, + required: true, + }, + }, + computed: { + showMetadata() { + const visibilityConditions = { + [PackageType.NUGET]: this.packageEntity.nuget_metadatum, + [PackageType.CONAN]: this.packageEntity.conan_metadatum, + [PackageType.MAVEN]: this.packageEntity.maven_metadatum, + }; + return visibilityConditions[this.packageEntity.package_type]; + }, + }, +}; +</script> + +<template> + <div v-if="showMetadata"> + <h3 class="gl-font-lg" data-testid="title">{{ __('Additional Metadata') }}</h3> + + <div class="gl-bg-gray-50 gl-inset-border-1-gray-100 gl-rounded-base" data-testid="main"> + <template v-if="packageEntity.nuget_metadatum"> + <details-row icon="project" padding="gl-p-4" dashed data-testid="nuget-source"> + <gl-sprintf :message="$options.i18n.sourceText"> + <template #link> + <gl-link :href="packageEntity.nuget_metadatum.project_url" target="_blank">{{ + packageEntity.nuget_metadatum.project_url + }}</gl-link> + </template> + </gl-sprintf> + </details-row> + <details-row icon="license" padding="gl-p-4" data-testid="nuget-license"> + <gl-sprintf :message="$options.i18n.licenseText"> + <template #link> + <gl-link :href="packageEntity.nuget_metadatum.license_url" target="_blank">{{ + packageEntity.nuget_metadatum.license_url + }}</gl-link> + </template> + </gl-sprintf> + </details-row> + </template> + + <details-row + v-else-if="packageEntity.conan_metadatum" + icon="information-o" + padding="gl-p-4" + data-testid="conan-recipe" + > + <gl-sprintf :message="$options.i18n.recipeText"> + <template #recipe>{{ packageEntity.name }}</template> + </gl-sprintf> + </details-row> + + <template v-else-if="packageEntity.maven_metadatum"> + <details-row icon="information-o" padding="gl-p-4" dashed data-testid="maven-app"> + <gl-sprintf :message="$options.i18n.appName"> + <template #name> + <strong>{{ packageEntity.maven_metadatum.app_name }}</strong> + </template> + </gl-sprintf> + </details-row> + <details-row icon="information-o" padding="gl-p-4" data-testid="maven-group"> + <gl-sprintf :message="$options.i18n.appGroup"> + <template #group> + <strong>{{ packageEntity.maven_metadatum.app_group }}</strong> + </template> + </gl-sprintf> + </details-row> + </template> + </div> + </div> +</template> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/composer_installation.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/composer_installation.vue new file mode 100644 index 00000000000..b3979a620f0 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/composer_installation.vue @@ -0,0 +1,65 @@ +<script> +import { GlLink, GlSprintf } from '@gitlab/ui'; +import { mapGetters, mapState } from 'vuex'; +import { s__ } from '~/locale'; +import { TrackingActions, TrackingLabels } from '~/packages/details/constants'; +import InstallationTitle from '~/packages_and_registries/package_registry/components/details/installation_title.vue'; +import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue'; + +export default { + name: 'ComposerInstallation', + components: { + InstallationTitle, + CodeInstruction, + GlLink, + GlSprintf, + }, + computed: { + ...mapState(['composerHelpPath']), + ...mapGetters(['composerRegistryInclude', 'composerPackageInclude', 'groupExists']), + }, + i18n: { + registryInclude: s__('PackageRegistry|Add composer registry'), + copyRegistryInclude: s__('PackageRegistry|Copy registry include'), + packageInclude: s__('PackageRegistry|Install package version'), + copyPackageInclude: s__('PackageRegistry|Copy require package include'), + infoLine: s__( + 'PackageRegistry|For more information on Composer packages in GitLab, %{linkStart}see the documentation.%{linkEnd}', + ), + }, + trackingActions: { ...TrackingActions }, + TrackingLabels, + installOptions: [{ value: 'composer', label: s__('PackageRegistry|Show Composer commands') }], +}; +</script> + +<template> + <div v-if="groupExists" data-testid="root-node"> + <installation-title package-type="composer" :options="$options.installOptions" /> + + <code-instruction + :label="$options.i18n.registryInclude" + :instruction="composerRegistryInclude" + :copy-text="$options.i18n.copyRegistryInclude" + :tracking-action="$options.trackingActions.COPY_COMPOSER_REGISTRY_INCLUDE_COMMAND" + :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + data-testid="registry-include" + /> + + <code-instruction + :label="$options.i18n.packageInclude" + :instruction="composerPackageInclude" + :copy-text="$options.i18n.copyPackageInclude" + :tracking-action="$options.trackingActions.COPY_COMPOSER_PACKAGE_INCLUDE_COMMAND" + :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + data-testid="package-include" + /> + <span data-testid="help-text"> + <gl-sprintf :message="$options.i18n.infoLine"> + <template #link="{ content }"> + <gl-link :href="composerHelpPath" target="_blank">{{ content }}</gl-link> + </template> + </gl-sprintf> + </span> + </div> +</template> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/conan_installation.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/conan_installation.vue new file mode 100644 index 00000000000..59b446e46b5 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/conan_installation.vue @@ -0,0 +1,59 @@ +<script> +import { GlLink, GlSprintf } from '@gitlab/ui'; +import { mapGetters, mapState } from 'vuex'; +import { s__ } from '~/locale'; +import { TrackingActions, TrackingLabels } from '~/packages/details/constants'; +import InstallationTitle from '~/packages_and_registries/package_registry/components/details/installation_title.vue'; +import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue'; + +export default { + name: 'ConanInstallation', + components: { + InstallationTitle, + CodeInstruction, + GlLink, + GlSprintf, + }, + computed: { + ...mapState(['conanHelpPath']), + ...mapGetters(['conanInstallationCommand', 'conanSetupCommand']), + }, + i18n: { + helpText: s__( + 'PackageRegistry|For more information on the Conan registry, %{linkStart}see the documentation%{linkEnd}.', + ), + }, + trackingActions: { ...TrackingActions }, + TrackingLabels, + installOptions: [{ value: 'conan', label: s__('PackageRegistry|Show Conan commands') }], +}; +</script> + +<template> + <div> + <installation-title package-type="conan" :options="$options.installOptions" /> + + <code-instruction + :label="s__('PackageRegistry|Conan Command')" + :instruction="conanInstallationCommand" + :copy-text="s__('PackageRegistry|Copy Conan Command')" + :tracking-action="$options.trackingActions.COPY_CONAN_COMMAND" + :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + /> + + <h3 class="gl-font-lg">{{ __('Registry setup') }}</h3> + + <code-instruction + :label="s__('PackageRegistry|Add Conan Remote')" + :instruction="conanSetupCommand" + :copy-text="s__('PackageRegistry|Copy Conan Setup Command')" + :tracking-action="$options.trackingActions.COPY_CONAN_SETUP_COMMAND" + :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + /> + <gl-sprintf :message="$options.i18n.helpText"> + <template #link="{ content }"> + <gl-link :href="conanHelpPath" target="_blank">{{ content }}</gl-link> + </template> + </gl-sprintf> + </div> +</template> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/dependency_row.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/dependency_row.vue new file mode 100644 index 00000000000..1a2202b23c8 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/dependency_row.vue @@ -0,0 +1,35 @@ +<script> +export default { + name: 'DependencyRow', + props: { + dependency: { + type: Object, + required: true, + }, + }, + computed: { + showVersion() { + return Boolean(this.dependency.version_pattern); + }, + }, +}; +</script> + +<template> + <div class="gl-responsive-table-row"> + <div class="table-section section-50"> + <strong class="gl-text-body">{{ dependency.name }}</strong> + <span v-if="dependency.target_framework" data-testid="target-framework" + >({{ dependency.target_framework }})</span + > + </div> + + <div + v-if="showVersion" + class="table-section section-50 gl-display-flex gl-md-justify-content-end" + data-testid="version-pattern" + > + <span class="gl-text-body">{{ dependency.version_pattern }}</span> + </div> + </div> +</template> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/file_sha.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/file_sha.vue new file mode 100644 index 00000000000..a25839be7e1 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/file_sha.vue @@ -0,0 +1,41 @@ +<script> +import { s__ } from '~/locale'; +import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; +import DetailsRow from '~/vue_shared/components/registry/details_row.vue'; + +export default { + name: 'FileSha', + components: { + DetailsRow, + ClipboardButton, + }, + props: { + sha: { + type: String, + required: true, + }, + title: { + type: String, + required: true, + }, + }, + i18n: { + copyButtonTitle: s__('PackageRegistry|Copy SHA'), + }, +}; +</script> + +<template> + <details-row dashed> + <div class="gl-px-4"> + {{ title }}: + {{ sha }} + <clipboard-button + :text="sha" + :title="$options.i18n.copyButtonTitle" + category="tertiary" + size="small" + /> + </div> + </details-row> +</template> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/installation_commands.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/installation_commands.vue new file mode 100644 index 00000000000..9ebfbbbf9e5 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/installation_commands.vue @@ -0,0 +1,55 @@ +<script> +import { PackageType, TERRAFORM_PACKAGE_TYPE } from '~/packages/shared/constants'; +import TerraformInstallation from '~/packages_and_registries/infrastructure_registry/components/terraform_installation.vue'; +import ComposerInstallation from './composer_installation.vue'; +import ConanInstallation from './conan_installation.vue'; +import MavenInstallation from './maven_installation.vue'; +import NpmInstallation from './npm_installation.vue'; +import NugetInstallation from './nuget_installation.vue'; +import PypiInstallation from './pypi_installation.vue'; + +export default { + name: 'InstallationCommands', + components: { + [PackageType.CONAN]: ConanInstallation, + [PackageType.MAVEN]: MavenInstallation, + [PackageType.NPM]: NpmInstallation, + [PackageType.NUGET]: NugetInstallation, + [PackageType.PYPI]: PypiInstallation, + [PackageType.COMPOSER]: ComposerInstallation, + [TERRAFORM_PACKAGE_TYPE]: TerraformInstallation, + }, + props: { + packageEntity: { + type: Object, + required: true, + }, + npmPath: { + type: String, + required: false, + default: '', + }, + npmHelpPath: { + type: String, + required: false, + default: '', + }, + }, + computed: { + installationComponent() { + return this.$options.components[this.packageEntity.package_type]; + }, + }, +}; +</script> + +<template> + <div v-if="installationComponent"> + <component + :is="installationComponent" + :name="packageEntity.name" + :registry-url="npmPath" + :help-url="npmHelpPath" + /> + </div> +</template> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/installation_title.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/installation_title.vue new file mode 100644 index 00000000000..43133bf7825 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/installation_title.vue @@ -0,0 +1,38 @@ +<script> +import PersistedDropdownSelection from '~/vue_shared/components/registry/persisted_dropdown_selection.vue'; + +export default { + name: 'InstallationTitle', + components: { + PersistedDropdownSelection, + }, + props: { + packageType: { + type: String, + required: true, + }, + options: { + type: Array, + required: true, + }, + }, + computed: { + storageKey() { + return `package_${this.packageType}_installation_instructions`; + }, + }, +}; +</script> + +<template> + <div class="gl-display-flex gl-justify-content-space-between gl-align-items-center"> + <h3 class="gl-font-lg">{{ __('Installation') }}</h3> + <div> + <persisted-dropdown-selection + :storage-key="storageKey" + :options="options" + @change="$emit('change', $event)" + /> + </div> + </div> +</template> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/maven_installation.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/maven_installation.vue new file mode 100644 index 00000000000..b035e557d21 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/maven_installation.vue @@ -0,0 +1,152 @@ +<script> +import { GlLink, GlSprintf } from '@gitlab/ui'; +import { mapGetters, mapState } from 'vuex'; +import { s__ } from '~/locale'; +import { TrackingActions, TrackingLabels } from '~/packages/details/constants'; +import InstallationTitle from '~/packages_and_registries/package_registry/components/details/installation_title.vue'; +import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue'; + +export default { + name: 'MavenInstallation', + components: { + InstallationTitle, + CodeInstruction, + GlLink, + GlSprintf, + }, + data() { + return { + instructionType: 'maven', + }; + }, + computed: { + ...mapState(['mavenHelpPath']), + ...mapGetters([ + 'mavenInstallationXml', + 'mavenInstallationCommand', + 'mavenSetupXml', + 'gradleGroovyInstalCommand', + 'gradleGroovyAddSourceCommand', + 'gradleKotlinInstalCommand', + 'gradleKotlinAddSourceCommand', + ]), + showMaven() { + return this.instructionType === 'maven'; + }, + showGroovy() { + return this.instructionType === 'groovy'; + }, + }, + i18n: { + xmlText: s__( + `PackageRegistry|Copy and paste this inside your %{codeStart}pom.xml%{codeEnd} %{codeStart}dependencies%{codeEnd} block.`, + ), + setupText: s__( + `PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}pom.xml%{codeEnd} file.`, + ), + helpText: s__( + 'PackageRegistry|For more information on the Maven registry, %{linkStart}see the documentation%{linkEnd}.', + ), + }, + trackingActions: { ...TrackingActions }, + TrackingLabels, + installOptions: [ + { value: 'maven', label: s__('PackageRegistry|Maven XML') }, + { value: 'groovy', label: s__('PackageRegistry|Gradle Groovy DSL') }, + { value: 'kotlin', label: s__('PackageRegistry|Gradle Kotlin DSL') }, + ], +}; +</script> + +<template> + <div> + <installation-title + package-type="maven" + :options="$options.installOptions" + @change="instructionType = $event" + /> + + <template v-if="showMaven"> + <p> + <gl-sprintf :message="$options.i18n.xmlText"> + <template #code="{ content }"> + <code>{{ content }}</code> + </template> + </gl-sprintf> + </p> + + <code-instruction + :instruction="mavenInstallationXml" + :copy-text="s__('PackageRegistry|Copy Maven XML')" + :tracking-action="$options.trackingActions.COPY_MAVEN_XML" + :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + multiline + /> + + <code-instruction + :label="s__('PackageRegistry|Maven Command')" + :instruction="mavenInstallationCommand" + :copy-text="s__('PackageRegistry|Copy Maven command')" + :tracking-action="$options.trackingActions.COPY_MAVEN_COMMAND" + :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + /> + + <h3 class="gl-font-lg">{{ s__('PackageRegistry|Registry setup') }}</h3> + <p> + <gl-sprintf :message="$options.i18n.setupText"> + <template #code="{ content }"> + <code>{{ content }}</code> + </template> + </gl-sprintf> + </p> + <code-instruction + :instruction="mavenSetupXml" + :copy-text="s__('PackageRegistry|Copy Maven registry XML')" + :tracking-action="$options.trackingActions.COPY_MAVEN_SETUP" + :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + multiline + /> + <gl-sprintf :message="$options.i18n.helpText"> + <template #link="{ content }"> + <gl-link :href="mavenHelpPath" target="_blank">{{ content }}</gl-link> + </template> + </gl-sprintf> + </template> + <template v-else-if="showGroovy"> + <code-instruction + class="gl-mb-5" + :label="s__('PackageRegistry|Gradle Groovy DSL install command')" + :instruction="gradleGroovyInstalCommand" + :copy-text="s__('PackageRegistry|Copy Gradle Groovy DSL install command')" + :tracking-action="$options.trackingActions.COPY_GRADLE_INSTALL_COMMAND" + :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + /> + <code-instruction + :label="s__('PackageRegistry|Add Gradle Groovy DSL repository command')" + :instruction="gradleGroovyAddSourceCommand" + :copy-text="s__('PackageRegistry|Copy add Gradle Groovy DSL repository command')" + :tracking-action="$options.trackingActions.COPY_GRADLE_ADD_TO_SOURCE_COMMAND" + :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + multiline + /> + </template> + <template v-else> + <code-instruction + class="gl-mb-5" + :label="s__('PackageRegistry|Gradle Kotlin DSL install command')" + :instruction="gradleKotlinInstalCommand" + :copy-text="s__('PackageRegistry|Copy Gradle Kotlin DSL install command')" + :tracking-action="$options.trackingActions.COPY_KOTLIN_INSTALL_COMMAND" + :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + /> + <code-instruction + :label="s__('PackageRegistry|Add Gradle Kotlin DSL repository command')" + :instruction="gradleKotlinAddSourceCommand" + :copy-text="s__('PackageRegistry|Copy add Gradle Kotlin DSL repository command')" + :tracking-action="$options.trackingActions.COPY_KOTLIN_ADD_TO_SOURCE_COMMAND" + :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + multiline + /> + </template> + </div> +</template> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/npm_installation.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/npm_installation.vue new file mode 100644 index 00000000000..c178d3e97e9 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/npm_installation.vue @@ -0,0 +1,103 @@ +<script> +import { GlLink, GlSprintf } from '@gitlab/ui'; +import { mapGetters, mapState } from 'vuex'; +import { s__ } from '~/locale'; +import { NpmManager, TrackingActions, TrackingLabels } from '~/packages/details/constants'; +import InstallationTitle from '~/packages_and_registries/package_registry/components/details/installation_title.vue'; +import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue'; + +export default { + name: 'NpmInstallation', + components: { + InstallationTitle, + CodeInstruction, + GlLink, + GlSprintf, + }, + data() { + return { + instructionType: 'npm', + }; + }, + computed: { + ...mapState(['npmHelpPath']), + ...mapGetters(['npmInstallationCommand', 'npmSetupCommand']), + npmCommand() { + return this.npmInstallationCommand(NpmManager.NPM); + }, + npmSetup() { + return this.npmSetupCommand(NpmManager.NPM); + }, + yarnCommand() { + return this.npmInstallationCommand(NpmManager.YARN); + }, + yarnSetupCommand() { + return this.npmSetupCommand(NpmManager.YARN); + }, + showNpm() { + return this.instructionType === 'npm'; + }, + }, + i18n: { + helpText: s__( + 'PackageRegistry|You may also need to setup authentication using an auth token. %{linkStart}See the documentation%{linkEnd} to find out more.', + ), + }, + trackingActions: { ...TrackingActions }, + TrackingLabels, + installOptions: [ + { value: 'npm', label: s__('PackageRegistry|Show NPM commands') }, + { value: 'yarn', label: s__('PackageRegistry|Show Yarn commands') }, + ], +}; +</script> + +<template> + <div> + <installation-title + package-type="npm" + :options="$options.installOptions" + @change="instructionType = $event" + /> + + <code-instruction + v-if="showNpm" + :instruction="npmCommand" + :copy-text="s__('PackageRegistry|Copy npm command')" + :tracking-action="$options.trackingActions.COPY_NPM_INSTALL_COMMAND" + :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + /> + + <code-instruction + v-else + :instruction="yarnCommand" + :copy-text="s__('PackageRegistry|Copy yarn command')" + :tracking-action="$options.trackingActions.COPY_YARN_INSTALL_COMMAND" + :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + /> + + <h3 class="gl-font-lg">{{ __('Registry setup') }}</h3> + + <code-instruction + v-if="showNpm" + :instruction="npmSetup" + :copy-text="s__('PackageRegistry|Copy npm setup command')" + :tracking-action="$options.trackingActions.COPY_NPM_SETUP_COMMAND" + :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + /> + + <code-instruction + v-else + :instruction="yarnSetupCommand" + :copy-text="s__('PackageRegistry|Copy yarn setup command')" + :tracking-action="$options.trackingActions.COPY_YARN_SETUP_COMMAND" + :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + /> + + <gl-sprintf :message="$options.i18n.helpText"> + <template #link="{ content }"> + <gl-link :href="npmHelpPath" target="_blank">{{ content }}</gl-link> + </template> + </gl-sprintf> + </div> +</template> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/nuget_installation.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/nuget_installation.vue new file mode 100644 index 00000000000..84493790b4d --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/nuget_installation.vue @@ -0,0 +1,58 @@ +<script> +import { GlLink, GlSprintf } from '@gitlab/ui'; +import { mapGetters, mapState } from 'vuex'; +import { s__ } from '~/locale'; +import { TrackingActions, TrackingLabels } from '~/packages/details/constants'; +import InstallationTitle from '~/packages_and_registries/package_registry/components/details/installation_title.vue'; +import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue'; + +export default { + name: 'NugetInstallation', + components: { + InstallationTitle, + CodeInstruction, + GlLink, + GlSprintf, + }, + computed: { + ...mapState(['nugetHelpPath']), + ...mapGetters(['nugetInstallationCommand', 'nugetSetupCommand']), + }, + i18n: { + helpText: s__( + 'PackageRegistry|For more information on the NuGet registry, %{linkStart}see the documentation%{linkEnd}.', + ), + }, + trackingActions: { ...TrackingActions }, + TrackingLabels, + installOptions: [{ value: 'nuget', label: s__('PackageRegistry|Show Nuget commands') }], +}; +</script> + +<template> + <div> + <installation-title package-type="nuget" :options="$options.installOptions" /> + + <code-instruction + :label="s__('PackageRegistry|NuGet Command')" + :instruction="nugetInstallationCommand" + :copy-text="s__('PackageRegistry|Copy NuGet Command')" + :tracking-action="$options.trackingActions.COPY_NUGET_INSTALL_COMMAND" + :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + /> + <h3 class="gl-font-lg">{{ __('Registry setup') }}</h3> + + <code-instruction + :label="s__('PackageRegistry|Add NuGet Source')" + :instruction="nugetSetupCommand" + :copy-text="s__('PackageRegistry|Copy NuGet Setup Command')" + :tracking-action="$options.trackingActions.COPY_NUGET_SETUP_COMMAND" + :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + /> + <gl-sprintf :message="$options.i18n.helpText"> + <template #link="{ content }"> + <gl-link :href="nugetHelpPath" target="_blank">{{ content }}</gl-link> + </template> + </gl-sprintf> + </div> +</template> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_files.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_files.vue new file mode 100644 index 00000000000..3c2876e902b --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_files.vue @@ -0,0 +1,165 @@ +<script> +import { GlLink, GlTable, GlDropdownItem, GlDropdown, GlIcon, GlButton } from '@gitlab/ui'; +import { last } from 'lodash'; +import { numberToHumanSize } from '~/lib/utils/number_utils'; +import { __ } from '~/locale'; +import FileSha from '~/packages_and_registries/package_registry/components/details/file_sha.vue'; +import Tracking from '~/tracking'; +import FileIcon from '~/vue_shared/components/file_icon.vue'; +import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; + +export default { + name: 'PackageFiles', + components: { + GlLink, + GlTable, + GlIcon, + GlDropdown, + GlDropdownItem, + GlButton, + FileIcon, + TimeAgoTooltip, + FileSha, + }, + mixins: [Tracking.mixin()], + props: { + packageFiles: { + type: Array, + required: false, + default: () => [], + }, + canDelete: { + type: Boolean, + default: false, + required: false, + }, + }, + computed: { + filesTableRows() { + return this.packageFiles.map((pf) => ({ + ...pf, + size: this.formatSize(pf.size), + pipeline: last(pf.pipelines), + })); + }, + showCommitColumn() { + return this.filesTableRows.some((row) => Boolean(row.pipeline?.id)); + }, + filesTableHeaderFields() { + return [ + { + key: 'name', + label: __('Name'), + }, + { + key: 'commit', + label: __('Commit'), + hide: !this.showCommitColumn, + }, + { + key: 'size', + label: __('Size'), + }, + { + key: 'created', + label: __('Created'), + class: 'gl-text-right', + }, + { + key: 'actions', + label: '', + hide: !this.canDelete, + class: 'gl-text-right', + tdClass: 'gl-w-4', + }, + ].filter((c) => !c.hide); + }, + }, + methods: { + formatSize(size) { + return numberToHumanSize(size); + }, + hasDetails(item) { + return item.file_sha256 || item.file_md5 || item.file_sha1; + }, + }, + i18n: { + deleteFile: __('Delete file'), + }, +}; +</script> + +<template> + <div> + <h3 class="gl-font-lg gl-mt-5">{{ __('Files') }}</h3> + <gl-table + :fields="filesTableHeaderFields" + :items="filesTableRows" + :tbody-tr-attr="{ 'data-testid': 'file-row' }" + > + <template #cell(name)="{ item, toggleDetails, detailsShowing }"> + <gl-button + v-if="hasDetails(item)" + :icon="detailsShowing ? 'angle-up' : 'angle-down'" + :aria-label="detailsShowing ? __('Collapse') : __('Expand')" + category="tertiary" + size="small" + @click="toggleDetails" + /> + <gl-link + :href="item.download_path" + class="gl-text-gray-500" + data-testid="download-link" + @click="$emit('download-file')" + > + <file-icon + :file-name="item.file_name" + css-classes="gl-relative file-icon" + class="gl-mr-1 gl-relative" + /> + <span>{{ item.file_name }}</span> + </gl-link> + </template> + + <template #cell(commit)="{ item }"> + <gl-link + v-if="item.pipeline && item.pipeline.project" + :href="item.pipeline.project.commit_url" + class="gl-text-gray-500" + data-testid="commit-link" + >{{ item.pipeline.git_commit_message }}</gl-link + > + </template> + + <template #cell(created)="{ item }"> + <time-ago-tooltip :time="item.created_at" /> + </template> + + <template #cell(actions)="{ item }"> + <gl-dropdown category="tertiary" right> + <template #button-content> + <gl-icon name="ellipsis_v" /> + </template> + <gl-dropdown-item data-testid="delete-file" @click="$emit('delete-file', item)"> + {{ $options.i18n.deleteFile }} + </gl-dropdown-item> + </gl-dropdown> + </template> + + <template #row-details="{ item }"> + <div + class="gl-display-flex gl-flex-direction-column gl-flex-grow-1 gl-bg-gray-10 gl-rounded-base gl-inset-border-1-gray-100" + > + <file-sha + v-if="item.file_sha256" + data-testid="sha-256" + title="SHA-256" + :sha="item.file_sha256" + /> + <file-sha v-if="item.file_md5" data-testid="md5" title="MD5" :sha="item.file_md5" /> + <file-sha v-if="item.file_sha1" data-testid="sha-1" title="SHA-1" :sha="item.file_sha1" /> + </div> + </template> + </gl-table> + </div> +</template> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_history.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_history.vue new file mode 100644 index 00000000000..0d7a73c12f1 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_history.vue @@ -0,0 +1,167 @@ +<script> +import { GlLink, GlSprintf } from '@gitlab/ui'; +import { first } from 'lodash'; +import { truncateSha } from '~/lib/utils/text_utility'; +import { s__, n__ } from '~/locale'; +import { HISTORY_PIPELINES_LIMIT } from '~/packages/details/constants'; +import HistoryItem from '~/vue_shared/components/registry/history_item.vue'; +import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; + +export default { + name: 'PackageHistory', + i18n: { + createdOn: s__('PackageRegistry|%{name} version %{version} was first created %{datetime}'), + createdByCommitText: s__('PackageRegistry|Created by commit %{link} on branch %{branch}'), + createdByPipelineText: s__( + 'PackageRegistry|Built by pipeline %{link} triggered %{datetime} by %{author}', + ), + publishText: s__('PackageRegistry|Published to the %{project} Package Registry %{datetime}'), + combinedUpdateText: s__( + 'PackageRegistry|Package updated by commit %{link} on branch %{branch}, built by pipeline %{pipeline}, and published to the registry %{datetime}', + ), + archivedPipelineMessageSingular: s__('PackageRegistry|Package has %{number} archived update'), + archivedPipelineMessagePlural: s__('PackageRegistry|Package has %{number} archived updates'), + }, + components: { + GlLink, + GlSprintf, + HistoryItem, + TimeAgoTooltip, + }, + props: { + packageEntity: { + type: Object, + required: true, + }, + projectName: { + type: String, + required: true, + }, + }, + data() { + return { + showDescription: false, + }; + }, + computed: { + pipelines() { + return this.packageEntity.pipelines || []; + }, + firstPipeline() { + return first(this.pipelines); + }, + lastPipelines() { + return this.pipelines.slice(1).slice(-HISTORY_PIPELINES_LIMIT); + }, + showPipelinesInfo() { + return Boolean(this.firstPipeline?.id); + }, + archiviedLines() { + return Math.max(this.pipelines.length - HISTORY_PIPELINES_LIMIT - 1, 0); + }, + archivedPipelineMessage() { + return n__( + this.$options.i18n.archivedPipelineMessageSingular, + this.$options.i18n.archivedPipelineMessagePlural, + this.archiviedLines, + ); + }, + }, + methods: { + truncate(value) { + return truncateSha(value); + }, + }, +}; +</script> + +<template> + <div class="issuable-discussion"> + <h3 class="gl-font-lg" data-testid="title">{{ __('History') }}</h3> + <ul class="timeline main-notes-list notes gl-mb-4" data-testid="timeline"> + <history-item icon="clock" data-testid="created-on"> + <gl-sprintf :message="$options.i18n.createdOn"> + <template #name> + <strong>{{ packageEntity.name }}</strong> + </template> + <template #version> + <strong>{{ packageEntity.version }}</strong> + </template> + <template #datetime> + <time-ago-tooltip :time="packageEntity.created_at" /> + </template> + </gl-sprintf> + </history-item> + + <template v-if="showPipelinesInfo"> + <!-- FIRST PIPELINE BLOCK --> + <history-item icon="commit" data-testid="first-pipeline-commit"> + <gl-sprintf :message="$options.i18n.createdByCommitText"> + <template #link> + <gl-link :href="firstPipeline.project.commit_url" + >#{{ truncate(firstPipeline.sha) }}</gl-link + > + </template> + <template #branch> + <strong>{{ firstPipeline.ref }}</strong> + </template> + </gl-sprintf> + </history-item> + <history-item icon="pipeline" data-testid="first-pipeline-pipeline"> + <gl-sprintf :message="$options.i18n.createdByPipelineText"> + <template #link> + <gl-link :href="firstPipeline.project.pipeline_url">#{{ firstPipeline.id }}</gl-link> + </template> + <template #datetime> + <time-ago-tooltip :time="firstPipeline.created_at" /> + </template> + <template #author>{{ firstPipeline.user.name }}</template> + </gl-sprintf> + </history-item> + </template> + + <!-- PUBLISHED LINE --> + <history-item icon="package" data-testid="published"> + <gl-sprintf :message="$options.i18n.publishText"> + <template #project> + <strong>{{ projectName }}</strong> + </template> + <template #datetime> + <time-ago-tooltip :time="packageEntity.created_at" /> + </template> + </gl-sprintf> + </history-item> + + <history-item v-if="archiviedLines" icon="history" data-testid="archived"> + <gl-sprintf :message="archivedPipelineMessage"> + <template #number> + <strong>{{ archiviedLines }}</strong> + </template> + </gl-sprintf> + </history-item> + + <!-- PIPELINES LIST ENTRIES --> + <history-item + v-for="pipeline in lastPipelines" + :key="pipeline.id" + icon="pencil" + data-testid="pipeline-entry" + > + <gl-sprintf :message="$options.i18n.combinedUpdateText"> + <template #link> + <gl-link :href="pipeline.project.commit_url">#{{ truncate(pipeline.sha) }}</gl-link> + </template> + <template #branch> + <strong>{{ pipeline.ref }}</strong> + </template> + <template #pipeline> + <gl-link :href="pipeline.project.pipeline_url">#{{ pipeline.id }}</gl-link> + </template> + <template #datetime> + <time-ago-tooltip :time="pipeline.created_at" /> + </template> + </gl-sprintf> + </history-item> + </ul> + </div> +</template> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/pypi_installation.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/pypi_installation.vue new file mode 100644 index 00000000000..21eba44a720 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/pypi_installation.vue @@ -0,0 +1,71 @@ +<script> +import { GlLink, GlSprintf } from '@gitlab/ui'; +import { mapGetters, mapState } from 'vuex'; +import { s__ } from '~/locale'; +import { TrackingActions, TrackingLabels } from '~/packages/details/constants'; +import InstallationTitle from '~/packages_and_registries/package_registry/components/details/installation_title.vue'; +import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue'; + +export default { + name: 'PyPiInstallation', + components: { + InstallationTitle, + CodeInstruction, + GlLink, + GlSprintf, + }, + computed: { + ...mapState(['pypiHelpPath']), + ...mapGetters(['pypiPipCommand', 'pypiSetupCommand']), + }, + i18n: { + setupText: s__( + `PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file.`, + ), + helpText: s__( + 'PackageRegistry|For more information on the PyPi registry, %{linkStart}see the documentation%{linkEnd}.', + ), + }, + trackingActions: { ...TrackingActions }, + TrackingLabels, + installOptions: [{ value: 'pypi', label: s__('PackageRegistry|Show PyPi commands') }], +}; +</script> + +<template> + <div> + <installation-title package-type="pypi" :options="$options.installOptions" /> + + <code-instruction + :label="s__('PackageRegistry|Pip Command')" + :instruction="pypiPipCommand" + :copy-text="s__('PackageRegistry|Copy Pip command')" + data-testid="pip-command" + :tracking-action="$options.trackingActions.COPY_PIP_INSTALL_COMMAND" + :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + /> + + <h3 class="gl-font-lg">{{ __('Registry setup') }}</h3> + <p> + <gl-sprintf :message="$options.i18n.setupText"> + <template #code="{ content }"> + <code>{{ content }}</code> + </template> + </gl-sprintf> + </p> + + <code-instruction + :instruction="pypiSetupCommand" + :copy-text="s__('PackageRegistry|Copy .pypirc content')" + data-testid="pypi-setup-content" + multiline + :tracking-action="$options.trackingActions.COPY_PYPI_SETUP_COMMAND" + :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + /> + <gl-sprintf :message="$options.i18n.helpText"> + <template #link="{ content }"> + <gl-link :href="pypiHelpPath" target="_blank">{{ content }}</gl-link> + </template> + </gl-sprintf> + </div> +</template> |