Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/components/Input/Base.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ defineExpose({
v-bind="props.noCorrect ? noCorrect : undefined"
@focus="emit('focus', $event)"
@blur="emit('blur', $event)"
class="bg-bg-subtle border border-border font-mono text-fg placeholder:text-fg-subtle transition-[border-color,outline-color] duration-300 hover:border-fg-subtle outline-2 outline-transparent outline-offset-2 focus:border-accent focus-visible:outline-accent/70 disabled:(opacity-50 cursor-not-allowed)"
class="appearance-none bg-bg-subtle border border-border font-mono text-fg placeholder:text-fg-subtle transition-[border-color,outline-color] duration-300 hover:border-fg-subtle outline-2 outline-transparent outline-offset-2 focus:border-accent focus-visible:outline-accent/70 disabled:(opacity-50 cursor-not-allowed)"
:class="{
'text-xs leading-[1.2] px-2 py-2 rounded-md': size === 'small',
'text-sm leading-none px-3 py-2.5 rounded-lg': size === 'medium',
'text-base leading-none px-6 py-3.5 h-14 rounded-xl': size === 'large',
'text-base leading-[1.4] px-6 py-4 rounded-xl': size === 'large',
}"
:disabled="
/** Catching Vue render-bug of invalid `disabled=false` attribute in the final HTML */
Expand Down
89 changes: 48 additions & 41 deletions app/components/Org/MembersPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const isLoadingTeams = shallowRef(false)
// Search/filter
const searchQuery = shallowRef('')
const filterRole = shallowRef<MemberRoleFilter>('all')
const filterTeam = shallowRef<string | null>(null)
const filterTeam = shallowRef<string>('')
const sortBy = shallowRef<'name' | 'role'>('name')
const sortOrder = shallowRef<'asc' | 'desc'>('asc')

Expand Down Expand Up @@ -362,18 +362,19 @@ watch(lastExecutionTime, () => {
</div>
<!-- Team filter -->
<div v-if="teamNames.length > 0">
<label for="team-filter" class="sr-only">{{ $t('org.members.filter_by_team') }}</label>
<select
<SelectField
:label="$t('org.members.filter_by_team')"
hidden-label
id="team-filter"
v-model="filterTeam"
name="team-filter"
class="px-2 py-1 font-mono text-xs bg-bg-subtle border border-border rounded text-fg transition-colors duration-200 focus:border-border-hover"
>
<option :value="null">{{ $t('org.members.all_teams') }}</option>
<option v-for="team in teamNames" :key="team" :value="team">
{{ team }}
</option>
</select>
block
size="sm"
:items="[
{ label: $t('org.members.all_teams'), value: '' },
...teamNames.map(team => ({ label: team, value: team })),
]"
/>
</div>
<div
class="flex items-center gap-1 text-xs"
Expand Down Expand Up @@ -462,22 +463,22 @@ watch(lastExecutionTime, () => {
<label :for="`role-${member.name}`" class="sr-only">{{
$t('org.members.change_role_for', { name: member.name })
}}</label>
<select
<SelectField
:label="$t('org.members.change_role_for', { name: member.name })"
hidden-label
:id="`role-${member.name}`"
:value="member.role"
:model-value="member.role"
:name="`role-${member.name}`"
class="px-1.5 py-0.5 font-mono text-xs bg-bg-subtle border border-border rounded text-fg transition-colors duration-200 focus:border-border-hover"
@change="
handleChangeRole(
member.name,
($event.target as HTMLSelectElement).value as 'developer' | 'admin' | 'owner',
)
"
>
<option value="developer">{{ getRoleLabel('developer') }}</option>
<option value="admin">{{ getRoleLabel('admin') }}</option>
<option value="owner">{{ getRoleLabel('owner') }}</option>
</select>
block
size="sm"
:items="[
{ label: getRoleLabel('developer'), value: 'developer' },
{ label: getRoleLabel('admin'), value: 'admin' },
{ label: getRoleLabel('owner'), value: 'owner' },
]"
:value="member.role"
@update:modelValue="value => handleChangeRole(member.name, value as MemberRole)"
/>
Comment thread
coderabbitai[bot] marked this conversation as resolved.
<!-- Remove button -->
<button
type="button"
Expand Down Expand Up @@ -528,30 +529,36 @@ watch(lastExecutionTime, () => {
size="small"
/>
<div class="flex items-center gap-2">
<label for="new-member-role" class="sr-only">{{ $t('org.members.role_label') }}</label>
<select
<SelectField
:label="$t('org.members.role_label')"
hidden-label
id="new-member-role"
v-model="newRole"
name="new-member-role"
class="flex-1 px-2 py-1.5 font-mono text-sm bg-bg border border-border rounded text-fg transition-colors duration-200 focus:border-border-hover"
>
<option value="developer">{{ $t('org.members.role.developer') }}</option>
<option value="admin">{{ $t('org.members.role.admin') }}</option>
<option value="owner">{{ $t('org.members.role.owner') }}</option>
</select>
block
class="flex-1"
size="sm"
:items="[
{ label: $t('org.members.role.developer'), value: 'developer' },
{ label: $t('org.members.role.admin'), value: 'admin' },
{ label: $t('org.members.role.owner'), value: 'owner' },
]"
/>
<!-- Team selection -->
<label for="new-member-team" class="sr-only">{{ $t('org.members.team_label') }}</label>
<select
<SelectField
:label="$t('org.members.team_label')"
hidden-label
id="new-member-team"
v-model="newTeam"
name="new-member-team"
class="flex-1 px-2 py-1.5 font-mono text-sm bg-bg border border-border rounded text-fg transition-colors duration-200 focus:border-border-hover"
>
<option value="">{{ $t('org.members.no_team') }}</option>
<option v-for="team in teamNames" :key="team" :value="team">
{{ team }}
</option>
</select>
block
class="flex-1"
size="sm"
:items="[
{ label: $t('org.members.no_team'), value: '' },
...teamNames.map(team => ({ label: team, value: team })),
]"
/>
<button
type="submit"
:disabled="!newUsername.trim() || isAddingMember"
Expand Down
52 changes: 25 additions & 27 deletions app/components/Package/AccessControls.vue
Original file line number Diff line number Diff line change
Expand Up @@ -243,41 +243,39 @@ watch(
<div v-if="showGrantAccess">
<form class="space-y-2" @submit.prevent="handleGrantAccess">
<div class="flex items-center gap-2">
<label for="grant-team-select" class="sr-only">{{
$t('package.access.select_team_label')
}}</label>
<select
<SelectField
:label="$t('package.access.select_team_label')"
hidden-label
id="grant-team-select"
v-model="selectedTeam"
name="grant-team"
class="flex-1 px-2 py-1.5 font-mono text-sm bg-bg-subtle border border-border rounded text-fg transition-colors duration-200 focus:border-border-hover"
block
size="sm"
:disabled="isLoadingTeams"
>
<option value="" disabled>
{{
isLoadingTeams
:items="[
{
label: isLoadingTeams
? $t('package.access.loading_teams')
: $t('package.access.select_team')
}}
</option>
<option v-for="team in teams" :key="team" :value="team">
{{ orgName }}:{{ team }}
</option>
</select>
</div>
<div class="flex items-center gap-2">
<label for="grant-permission-select" class="sr-only">{{
$t('package.access.permission_label')
}}</label>
<select
: $t('package.access.select_team'),
value: '',
disabled: true,
},
...teams.map(team => ({ label: `${orgName}:${team}`, value: team })),
]"
/>
<SelectField
:label="$t('package.access.permission_label')"
hidden-label
id="grant-permission-select"
v-model="permission"
name="grant-permission"
class="flex-1 px-2 py-1.5 font-mono text-sm bg-bg-subtle border border-border rounded text-fg transition-colors duration-200 focus:border-border-hover"
>
<option value="read-only">{{ $t('package.access.permission.read_only') }}</option>
<option value="read-write">{{ $t('package.access.permission.read_write') }}</option>
</select>
block
size="sm"
:items="[
{ label: $t('package.access.permission.read_only'), value: 'read-only' },
{ label: $t('package.access.permission.read_write'), value: 'read-write' },
]"
/>
<button
type="submit"
:disabled="!selectedTeam || isGranting"
Expand Down
8 changes: 4 additions & 4 deletions app/components/Package/Dependencies.vue
Original file line number Diff line number Diff line change
Expand Up @@ -95,15 +95,15 @@ const numberFormatter = useNumberFormatter()
{{ dep }}
</LinkBase>
<span class="flex items-center gap-1 max-w-[40%]" dir="ltr">
<span
<TooltipApp
v-if="outdatedDeps[dep]"
class="shrink-0"
class="shrink-0 p-2 -m-2"
:class="getVersionClass(outdatedDeps[dep])"
:title="getOutdatedTooltip(outdatedDeps[dep], $t)"
aria-hidden="true"
:text="getOutdatedTooltip(outdatedDeps[dep], $t)"
>
<span class="i-carbon:warning-alt w-3 h-3" />
</span>
</TooltipApp>
<LinkBase
v-if="getVulnerableDepInfo(dep)"
:to="packageRoute(dep, getVulnerableDepInfo(dep)!.version)"
Expand Down
48 changes: 14 additions & 34 deletions app/components/Package/DownloadAnalytics.vue
Original file line number Diff line number Diff line change
Expand Up @@ -1474,44 +1474,24 @@ const chartConfig = computed(() => {
<div class="w-full relative" id="download-analytics" :aria-busy="pending ? 'true' : 'false'">
<div class="w-full mb-4 flex flex-col gap-3">
<div class="flex flex-col sm:flex-row gap-3 sm:gap-2 sm:items-end">
<div class="flex flex-col gap-1 sm:shrink-0">
<label
for="granularity"
class="text-3xs font-mono text-fg-subtle tracking-wide uppercase"
>
{{ $t('package.trends.granularity') }}
</label>

<div
class="flex items-center bg-bg-subtle border border-border rounded-md overflow-hidden"
>
<select
id="granularity"
v-model="selectedGranularity"
:disabled="pending"
class="w-full px-4 py-3 leading-none bg-bg-subtle font-mono text-sm text-fg outline-none appearance-none focus-visible:outline-accent/70"
>
<option value="daily">
{{ $t('package.trends.granularity_daily') }}
</option>
<option value="weekly">
{{ $t('package.trends.granularity_weekly') }}
</option>
<option value="monthly">
{{ $t('package.trends.granularity_monthly') }}
</option>
<option value="yearly">
{{ $t('package.trends.granularity_yearly') }}
</option>
</select>
</div>
</div>
<SelectField
:label="$t('package.trends.granularity')"
id="granularity"
v-model="selectedGranularity"
:disabled="pending"
:items="[
{ label: $t('package.trends.granularity_daily'), value: 'daily' },
{ label: $t('package.trends.granularity_weekly'), value: 'weekly' },
{ label: $t('package.trends.granularity_monthly'), value: 'monthly' },
{ label: $t('package.trends.granularity_yearly'), value: 'yearly' },
]"
/>

<div class="grid grid-cols-2 gap-2 flex-1">
<div class="flex flex-col gap-1">
<label
for="startDate"
class="text-3xs font-mono text-fg-subtle tracking-wide uppercase"
class="text-2xs font-mono text-fg-subtle tracking-wide uppercase"
>
{{ $t('package.trends.start_date') }}
</label>
Expand All @@ -1532,7 +1512,7 @@ const chartConfig = computed(() => {
</div>

<div class="flex flex-col gap-1">
<label for="endDate" class="text-3xs font-mono text-fg-subtle tracking-wide uppercase">
<label for="endDate" class="text-2xs font-mono text-fg-subtle tracking-wide uppercase">
{{ $t('package.trends.end_date') }}
</label>
<div class="relative flex items-center">
Expand Down
8 changes: 4 additions & 4 deletions app/components/Package/InstallScripts.vue
Original file line number Diff line number Diff line change
Expand Up @@ -115,18 +115,18 @@ const isExpanded = shallowRef(false)
{{ dep }}
</LinkBase>
<span class="flex items-center gap-1">
<span
<TooltipApp
v-if="
outdatedNpxDeps[dep] &&
outdatedNpxDeps[dep].resolved !== outdatedNpxDeps[dep].latest
"
class="shrink-0"
class="shrink-0 p-2 -m-2"
:class="getVersionClass(outdatedNpxDeps[dep])"
:title="getOutdatedTooltip(outdatedNpxDeps[dep], $t)"
aria-hidden="true"
:text="getOutdatedTooltip(outdatedNpxDeps[dep], $t)"
>
<span class="i-carbon:warning-alt w-3 h-3" />
</span>
</TooltipApp>
<span
class="font-mono text-xs text-end truncate"
:class="getVersionClass(outdatedNpxDeps[dep])"
Expand Down
28 changes: 8 additions & 20 deletions app/components/Package/ListControls.vue
Original file line number Diff line number Diff line change
Expand Up @@ -73,26 +73,14 @@ const showFilteredCount = computed(() => {
</div>

<!-- Sort select -->
<div class="relative shrink-0 flex">
<label for="package-sort" class="sr-only">{{ $t('package.list.sort_label') }}</label>
<div class="relative">
<select
id="package-sort"
v-model="sortValue"
class="appearance-none bg-bg-subtle border border-border rounded-lg ps-3 pe-8 py-3 leading-none font-mono text-sm text-fg transition-colors duration-200 focus:(border-border-hover outline-none) hover:border-border-hover"
>
<option v-for="option in sortOptions" :key="option.value" :value="option.value">
{{ option.label }}
</option>
</select>
<div
class="absolute inset-ie-3 top-1/2 -translate-y-1/2 text-fg-subtle pointer-events-none"
aria-hidden="true"
>
<div class="i-carbon:chevron-down w-4 h-4" />
</div>
</div>
</div>
<SelectField
:label="$t('package.list.sort_label')"
hidden-label
id="package-sort"
class="relative shrink-0"
v-model="sortValue"
:items="sortOptions.map(option => ({ label: option.label, value: option.value }))"
/>
</div>

<!-- Filtered count indicator -->
Expand Down
Loading
Loading