mirror of
https://github.com/bitwarden/server.git
synced 2025-06-30 23:52:50 -05:00
[AC-1081] Merge feature/billing-obfuscation (#2665)
* [EC-1014] Create Organization Status (Pending/Created) (#2610) * [EC-427] Add columns 'Type' and 'BillingPhone' to Provider table * [EC-427] Provider table Type and BillingPhone MySql migrations * [EC-427] Provider table Type and BillingPhone Postgres migrations * [EC-427] Add mysql migration script * [EC-427] Add mysql migration script * [EC-427] Updated Provider sql script to include default column value * [EC-427] Removed default value from Provider.Type column * [EC-427] Changed migration script to include a default value constraint instead of updating the null type * [EC-427] Updated Sql project Provider table script * [EC-427] Changed migration script to use 'Create OR Alter' for views and sprocs * [EC-427] Added default values for 'BillingPhone' and 'Type' fields on sprocs [dbo].[Provider_Create] and [dbo].[Provider_Update] * [EC-427] Adjusting metadata in migration script * [EC-427] Updated Provider sprocs SQL script files * [EC-427] Fixed migration script * [EC-427] Added sqlite migration * [EC-427] Add missing Provider_Update sproc default value * [EC-427] Added missing GO action to migration script * [EC-428] Redirect to Edit after creating Provider * Revert "[EC-428] Redirect to Edit after creating Provider" This reverts commit6347bca1ed
. * [EC-1014] Create OrganizationStatusType and add Status column to Organizations table * [EC-1014] Added EF migrations * [EC-1014] dotnet format * [EC-1014] Changed Organization.Status from SMALLINT to TINYINT * [EC-1014] Set Organization.Status default value = 1 * [EC-1014] Setting Organization.Status default value as 1 * [EC-459 / EC-428] Admin panel: Add Provider Type to list and creation flow (#2593) * [EC-427] Add columns 'Type' and 'BillingPhone' to Provider table * [EC-427] Provider table Type and BillingPhone MySql migrations * [EC-427] Provider table Type and BillingPhone Postgres migrations * [EC-427] Add mysql migration script * [EC-427] Add mysql migration script * [EC-427] Updated Provider sql script to include default column value * [EC-427] Removed default value from Provider.Type column * [EC-427] Changed migration script to include a default value constraint instead of updating the null type * [EC-427] Updated Sql project Provider table script * [EC-427] Changed migration script to use 'Create OR Alter' for views and sprocs * [EC-427] Added default values for 'BillingPhone' and 'Type' fields on sprocs [dbo].[Provider_Create] and [dbo].[Provider_Update] * [EC-427] Adjusting metadata in migration script * [EC-427] Updated Provider sprocs SQL script files * [EC-427] Fixed migration script * [EC-427] Added sqlite migration * [EC-427] Add missing Provider_Update sproc default value * [EC-427] Added missing GO action to migration script * [EC-459] Added Type column to Providers list * [EC-428] Added Type, BusinessName and BillingEmail to CreateProviderModel * [EC-428] Updated Create Provider view to include new fields * [EC-428] Updated ProviderService to not create a ProviderUser for the type Reseller * [EC-428] Added custom validation for Provider fields depending on selected Type * [EC-428] Redirect to Edit after creating Provider * [EC-428] Setting Provider status as Created for Resellers * [EC-428] Redirect on Provider creation depending if self host server * [EC-428] Split ProviderService.CreateAsync into two methods: CreateMspAsync and CreateResellerAsync * [EC-428] Created ICreateProviderCommand and added service for injection on Admin.Startup * [EC-428] Modified Provider views to use DisplayName attribute values * [EC-428] Moved ICreateProviderCommand to Core project * [EC-428] Adding ICreateProviderCommand injection next to IProviderService * [EC-428] Moved CreateProviderCommand to Commercial.Core project * [EC-459] Added Type column to Providers list * [EC-428] Added Type, BusinessName and BillingEmail to CreateProviderModel * [EC-428] Updated Create Provider view to include new fields * [EC-428] Updated ProviderService to not create a ProviderUser for the type Reseller * [EC-428] Added custom validation for Provider fields depending on selected Type * [EC-428] Redirect to Edit after creating Provider * [EC-428] Setting Provider status as Created for Resellers * [EC-428] Redirect on Provider creation depending if self host server * [EC-428] Split ProviderService.CreateAsync into two methods: CreateMspAsync and CreateResellerAsync * [EC-428] Created ICreateProviderCommand and added service for injection on Admin.Startup * [EC-428] Modified Provider views to use DisplayName attribute values * [EC-428] Moved ICreateProviderCommand to Core project * [EC-428] Adding ICreateProviderCommand injection next to IProviderService * [EC-428] Moved CreateProviderCommand to Commercial.Core project * [EC-428] Moved CreateProviderCommand to namespace Bit.Commercial.Core.Providers * [EC-429] Provider details screen updated with Type, BillingPhone and Organization details (#2666) * [EC-430] Admin portal: Update organization information screen (#2672) * [EC-430] Added ProviderOrganizationProviderDetailsView to get Provider details for an Organization * [EC-430] Added Provider information to Organization Edit/View on Admin panel * [EC-430] Remove "Add to Reseller" button * [EC-430] Removed unused property OrganizationEditModel.ClientOwnerEmail * [EC-430] Replaced IProviderOrganizationRepository.GetProviderDetailsByOrganizationAsync with IProviderRepository.GetByOrganizationIdAsync * [EC-430] Deleted ProviderOrganizationProviderDetails and ProviderOrganizationProviderDetailsReadByOrganizationIdQuery * [EC-429] Only show Create/Add Existing Organization buttons for Reseller providers (#2723) * [EC-432] Add existing Organizations to Provider (#2683) * [EC-432] Added ProviderOrganizationUnassignedOrganizationDetails_Search stored procedure * [EC-432] Added IProviderOrganizationRepository.SearchAsync * [EC-432] Created controller ProviderOrganizationsController to assign Organizations to a Provider * [EC-432] Filter existing organizations by plans Enterprise or Team * [EC-432] Existing Organization name links to edit page * [EC-432] EF filtering out existing organizations by plan type enterprise or teams * [EC-432] Creating multiple ProviderOrganization records * [EC-432] Added ProviderOrganizationUnassignedOrganizationDetails_Search stored procedure * [EC-432] Added IProviderOrganizationRepository.SearchAsync * [EC-432] Created controller ProviderOrganizationsController to assign Organizations to a Provider * [EC-432] Filter existing organizations by plans Enterprise or Team * [EC-432] Existing Organization name links to edit page * [EC-432] EF filtering out existing organizations by plan type enterprise or teams * [EC-432] Creating multiple ProviderOrganization records * [EC-432] Renamed migration script and added missing sproc * [EC-432] Saving multiple events for the created ProviderOrganizations * [EC-432] Included unit testing for ProviderService.AddOrganizations and EventService.LogProviderOrganizationEventsAsync * [EC-432] Removed async from NoopEventService.LogProviderOrganizationEventsAsync * [EC-432] Remove unused dependency setup in ProviderServiceTests.AddOrganizations_Success * [EC-432] Renamed AddOrganizations to AddOrganizationsToReseller and removed addingUserId and key arguments * [EC-432] Added DisplayName attributes to ProviderOrganizationViewModel and used them in the view * [EC-432] Reverted changes to input fields * [EC-432] Moved unassigned organizations search to Organizations repo * [EC-432] Moved AddExistingOrganization action to ProvidersController * [EC-432] dotnet format * [EC-432] Fixed unit test issues * [EC-432] Removed unnecessary Html.DisplayNameFor for labels * [EC-432] Renamed OrganizationSearchViewModel to OrganizationUnassignedToProviderSearchViewModel * [EC-432] Modified IEventService.LogProviderOrganizationEventsAsync to receive an IEnumerable as parameter * [EC-432] Updated IProviderOrganizationRepository and replaced CreateWithManyOrganizations method with CreateManyAsync * [EC-432] Deleted ProviderOrganization_CreateWithManyOrganizations * [AC-432] Simplified Organization_UnassignedToProviderSearch query * [AC-432] Removed unnecessary setup * [EC-432] Checking if stored procedure exists before creating * [EC-432] Renamed migration file to recent date * [EC-435] Admin Portal: Add new Organization creation flow UI (#2707) * [EC-435] Created _OrganizationForm partial view. Added actions for creating an Organization assigned to a provider * [EC-435] Remove logic for creating an organization * [EC-435] Created partial view _OrganizationFormScripts * [EC-435] Remove unused ReferenceEventType * [EC-435] Added TODO comment on Organization Create * [EC-435] Checking if Provider type is Reseller on creating new assigned organization * [EC-435] Setting the Organization plan type as TeamsMonthly by default when adding to a provider * [EC-435] Removing unused buttons * [EC-435] Switched hidden fields to form submit route value * [EC-435] Moved _OrganizationForm and _OrganizationFormScripts to Shared folder * [EC-435] Moved Create organization actions from OrganizationsController to ProvidersController * [EC-435] Fixing bug on saving Organization that would have BillingEmail as null * [EC-435] Added null check to Provider * [EC-435] Moved trial buttons script logic to Edit view * [AC-431] Add new organization invite process (#2737) * [EC-435] Created _OrganizationForm partial view. Added actions for creating an Organization assigned to a provider * [EC-435] Remove logic for creating an organization * [EC-435] Created partial view _OrganizationFormScripts * [EC-435] Remove unused ReferenceEventType * [EC-435] Added TODO comment on Organization Create * [EC-435] Checking if Provider type is Reseller on creating new assigned organization * [EC-435] Setting the Organization plan type as TeamsMonthly by default when adding to a provider * [EC-435] Removing unused buttons * [EC-435] Switched hidden fields to form submit route value * [EC-435] Moved _OrganizationForm and _OrganizationFormScripts to Shared folder * [EC-435] Moved Create organization actions from OrganizationsController to ProvidersController * [AC-431] Added new ReferenceEventType OrganizationCreatedByAdmin * [AC-431] Added method IOrganizationService.CreateOrganization * [AC-431] Creating new Organization with Pending status and assigning to Provider * [AC-431] Added method to IMailService to send invitation to initialize org * [AC-431] Added methods CreatePendingOrganization and InitPendingOrganization to IOrganizationService * [AC-431] Org invite includes initOrganization parameter * [AC-431] Modified existing Accept organization user action to initialize org * [AC-431] Updated ProvidersController method name * [AC-431] Created OrganizationUserInitInvitedViewModel to link to 'accept-init-organization' url * [AC-431] Added action AcceptInit to OrganizationUsersController * [AC-431] Resend owner invite * [AC-431] dotnet format * [AC-431] Removed unused parameter 'addingUserId' from IProviderService.AddOrganization * [AC-431] Removed setting manual values for CreationDate and RevisionDate * [AC-431] Updated OrganizationService.InitPendingOrganization to throw exceptions when the Organization does not meet the required criteria * [AC-431] Modified OrganizationUserInitInvitedViewModel to inherit properties from OrganizationUserInvitedViewModel * [AC-431] Removed unecessary parameter check * [AC-431] Moved method description to IOrganizationService.InitPendingOrganization * [AC-431] Moved ApplicationCacheService.UpsertOrganizationAbilityAsync and ReferenceEventService.RaiseEventAsync to OrganizationService * [AC-431] Creating collection after creating organization * [EC-435] Fixing bug on saving Organization that would have BillingEmail as null * [AC-431] Deleted OrganizationUserInitInvitedViewModel and added parameter InitOrganization to OrganizationUserInvitedViewModel.cs * [AC-431] Checking if the user has any existing SingleOrg policies before initializing an Org * [AC-431] Remove commented code * [EC-435] Added null check to Provider * [EC-435] Moved trial buttons script logic to Edit view * [AC-431] Added EncryptedString attribute to OrganizationUserAcceptInitRequestModel.CollectionName * [AC-431] Refactored plan check condition * [AC-431] Remove duplicate _applicationCacheService.UpsertOrganizationAbilityAsync call * [AC-431] Removed IMailService.SendOrganizationInitInviteEmailAsync * [AC-431] Added parameters ClaimsPrincipal and IUserService to IOrganizationService.CreatePendingOrganization * [AC-434] Hide Billing screen for Reseller clients (#2783) * [AC-434] Added ProviderType to ProfileOrganizationResponseModel * [AC-434] Migration script * [AC-434] Fixed indentation on migration script * [AC-434] Hiding sensitive subscription data if the user does not have permissions * [AC-434] Fixed missing dependency in unit test * [AC-434] Altered BillingSubscription.Amount and BillingSubscriptionUpcomingInvoice.Amount to nullable * [AC-434] Replaced CurrentContext.ManageBilling with ViewBillingHistory, ViewSubscription, EditSubscription and EditPaymentMethods * [AC-434] Reverted change on BillingSubscription.Amount and now setting Subscription.Items = null when User does not have permission * [AC-434] Added ProviderOrganizationProviderDetails_ReadByUserId * [AC-434] Added IProviderOrganizationRepository.GetManyByUserAsync * [AC-434] Added CurrentContext.GetOrganizationProviderDetails * [AC-434] Remove unneeded join Organization table * [AC-1255] Search Existing Organizations by partial Email (#2830) * [AC-1255] Added email search field input validation * [AC-1255] Reverted added email pattern * [AC-1255] Modified Organization search by Email to search using substring * [AC-1276] Displaying an Organizations pending owners if the Organization is in a Pending status (#2834) * [AC-432] Checking that an existing Organization is not assigned to any Provider before being assigned (#2840) * [AC-432] Checking if any of the selected Organizations is already assigned to a Provider * [AC-432] Changed ProviderOrganization_ReadByOrganizationIds to only get count * [AC-432] Replaced IProviderOrganizationRepository.GetCountByOrganizationIdsAsync with call to IProviderOrganizationRepository.GetByOrganizationId * [AC-432] undo new line * [AC-432] Fixed unit test * Revert "[AC-432] Replaced IProviderOrganizationRepository.GetCountByOrganizationIdsAsync with call to IProviderOrganizationRepository.GetByOrganizationId" This reverts commitee6e095e88
. # Conflicts: # util/Migrator/DbScripts/2023-03-22_00_ProviderAddExistingOrganizations.sql * [AC-432] Created new migration script for ProviderOrganization_ReadCountByOrganizationIds
This commit is contained in:
@ -1,21 +1,20 @@
|
||||
@model OrganizationEditModel
|
||||
@{
|
||||
ViewData["Title"] = "Organization: " + Model.Organization.Name;
|
||||
ViewData["Title"] = (Model.Provider != null ? "Client " : string.Empty) + "Organization: " + Model.Organization.Name;
|
||||
}
|
||||
|
||||
@section Scripts {
|
||||
@await Html.PartialAsync("_OrganizationFormScripts")
|
||||
|
||||
<script>
|
||||
(() => {
|
||||
document.getElementById('teams-trial').addEventListener('click', () => {
|
||||
if (document.getElementById('@(nameof(Model.PlanType))').value !==
|
||||
'@((byte)Bit.Core.Enums.PlanType.Free)') {
|
||||
if (document.getElementById('@(nameof(Model.PlanType))').value !== '@((byte)Bit.Core.Enums.PlanType.Free)') {
|
||||
alert('Organization is not on a free plan.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Plan
|
||||
document.getElementById('@(nameof(Model.PlanType))').value =
|
||||
'@((byte)Bit.Core.Enums.PlanType.TeamsAnnually)';
|
||||
document.getElementById('@(nameof(Model.PlanType))').value = '@((byte)Bit.Core.Enums.PlanType.TeamsAnnually)';
|
||||
document.getElementById('@(nameof(Model.Plan))').value = 'Teams (Trial)';
|
||||
document.getElementById('@(nameof(Model.Seats))').value = '10';
|
||||
document.getElementById('@(nameof(Model.MaxCollections))').value = '';
|
||||
@ -38,19 +37,14 @@
|
||||
document.getElementById('@(nameof(Model.LicenseKey))').value = '@Model.RandomLicenseKey';
|
||||
document.getElementById('@(nameof(Model.ExpirationDate))').value = '@Model.FourteenDayExpirationDate';
|
||||
document.getElementById('@(nameof(Model.SalesAssistedTrialStarted))').value = true;
|
||||
|
||||
});
|
||||
|
||||
document.getElementById('enterprise-trial').addEventListener('click', () => {
|
||||
if (document.getElementById('@(nameof(Model.PlanType))').value !==
|
||||
'@((byte)Bit.Core.Enums.PlanType.Free)') {
|
||||
if (document.getElementById('@(nameof(Model.PlanType))').value !== '@((byte)Bit.Core.Enums.PlanType.Free)') {
|
||||
alert('Organization is not on a free plan.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Plan
|
||||
document.getElementById('@(nameof(Model.PlanType))').value =
|
||||
'@((byte)Bit.Core.Enums.PlanType.EnterpriseAnnually)';
|
||||
document.getElementById('@(nameof(Model.PlanType))').value = '@((byte)Bit.Core.Enums.PlanType.EnterpriseAnnually)';
|
||||
document.getElementById('@(nameof(Model.Plan))').value = 'Enterprise (Trial)';
|
||||
document.getElementById('@(nameof(Model.Seats))').value = '10';
|
||||
document.getElementById('@(nameof(Model.MaxCollections))').value = '';
|
||||
@ -73,260 +67,24 @@
|
||||
document.getElementById('@(nameof(Model.LicenseKey))').value = '@Model.RandomLicenseKey';
|
||||
document.getElementById('@(nameof(Model.ExpirationDate))').value = '@Model.FourteenDayExpirationDate';
|
||||
document.getElementById('@(nameof(Model.SalesAssistedTrialStarted))').value = true;
|
||||
|
||||
});
|
||||
|
||||
document.getElementById('@(nameof(Model.PlanType))').addEventListener('change', () => {
|
||||
const selectEl = document.getElementById('@(nameof(Model.PlanType))');
|
||||
const selectText = selectEl.options[selectEl.selectedIndex].text;
|
||||
document.getElementById('@(nameof(Model.Plan))').value = selectText;
|
||||
});
|
||||
|
||||
document.getElementById('gateway-customer-link').addEventListener('click', () => {
|
||||
const gateway = document.getElementById('@(nameof(Model.Gateway))');
|
||||
const customerId = document.getElementById('@(nameof(Model.GatewayCustomerId))');
|
||||
if (!gateway || gateway.value === '' || !customerId || customerId.value === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gateway.value === '@((byte)Bit.Core.Enums.GatewayType.Stripe)') {
|
||||
window.open('https://dashboard.stripe.com/customers/' + customerId.value, '_blank');
|
||||
} else if (gateway.value === '@((byte)Bit.Core.Enums.GatewayType.Braintree)') {
|
||||
window.open('https://www.braintreegateway.com/merchants/@(Model.BraintreeMerchantId)/'
|
||||
+ customerId.value, '_blank');
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('gateway-subscription-link').addEventListener('click', () => {
|
||||
const gateway = document.getElementById('@(nameof(Model.Gateway))');
|
||||
const subId = document.getElementById('@(nameof(Model.GatewaySubscriptionId))');
|
||||
if (!gateway || gateway.value === '' || !subId || subId.value === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gateway.value === '@((byte)Bit.Core.Enums.GatewayType.Stripe)') {
|
||||
window.open('https://dashboard.stripe.com/subscriptions/' + subId.value, '_blank');
|
||||
} else if (gateway.value === '@((byte)Bit.Core.Enums.GatewayType.Braintree)') {
|
||||
window.open('https://www.braintreegateway.com/merchants/@(Model.BraintreeMerchantId)/' +
|
||||
'subscriptions/' + subId.value, '_blank');
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
}
|
||||
|
||||
<h1>Organization <small>@Model.Organization.Name</small></h1>
|
||||
<h1>@(Model.Provider != null ? "Client " : string.Empty)Organization <small>@Model.Organization.Name</small></h1>
|
||||
|
||||
@if (Model.Provider != null)
|
||||
{
|
||||
<h2>Provider Relationship</h2>
|
||||
@await Html.PartialAsync("_ProviderInformation", Model.Provider)
|
||||
}
|
||||
<h2>Organization Information</h2>
|
||||
@await Html.PartialAsync("_ViewInformation", Model)
|
||||
<h2>Billing Information</h2>
|
||||
@await Html.PartialAsync("_BillingInformation",
|
||||
new BillingInformationModel { BillingInfo = Model.BillingInfo, OrganizationId = Model.Organization.Id })
|
||||
<form method="post" id="edit-form">
|
||||
<input asp-for="SalesAssistedTrialStarted" type="hidden">
|
||||
<h2>General</h2>
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="Name"></label>
|
||||
<input type="text" class="form-control" asp-for="Name" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-check mb-3">
|
||||
<input type="checkbox" class="form-check-input" asp-for="Enabled">
|
||||
<label class="form-check-label" asp-for="Enabled"></label>
|
||||
</div>
|
||||
<h2>Business Information</h2>
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="BusinessName"></label>
|
||||
<input type="text" class="form-control" asp-for="BusinessName">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2>Plan</h2>
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="PlanType"></label>
|
||||
<select class="form-control" asp-for="PlanType"
|
||||
asp-items="Html.GetEnumSelectList<Bit.Core.Enums.PlanType>()"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="Plan"></label>
|
||||
<input type="text" class="form-control" asp-for="Plan" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="Seats"></label>
|
||||
<input type="number" class="form-control" asp-for="Seats" min="1">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="MaxCollections"></label>
|
||||
<input type="number" class="form-control" asp-for="MaxCollections" min="1">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="MaxStorageGb"></label>
|
||||
<input type="number" class="form-control" asp-for="MaxStorageGb" min="1">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">
|
||||
<div class="form-group">
|
||||
<label asp-for="MaxAutoscaleSeats"></label>
|
||||
<input type="number" class="form-control" asp-for="MaxAutoscaleSeats" min="1">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2>Features</h2>
|
||||
<div class="row mb-3">
|
||||
<div class="col-4">
|
||||
<h3>General</h3>
|
||||
<div class="form-check mb-2">
|
||||
<input type="checkbox" class="form-check-input" asp-for="SelfHost">
|
||||
<label class="form-check-label" asp-for="SelfHost"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="Use2fa">
|
||||
<label class="form-check-label" asp-for="Use2fa"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UseApi">
|
||||
<label class="form-check-label" asp-for="UseApi"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UseGroups">
|
||||
<label class="form-check-label" asp-for="UseGroups"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UsePolicies">
|
||||
<label class="form-check-label" asp-for="UsePolicies"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UseSso">
|
||||
<label class="form-check-label" asp-for="UseSso"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UseKeyConnector">
|
||||
<label class="form-check-label" asp-for="UseKeyConnector"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UseScim">
|
||||
<label class="form-check-label" asp-for="UseScim"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UseDirectory">
|
||||
<label class="form-check-label" asp-for="UseDirectory"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UseEvents">
|
||||
<label class="form-check-label" asp-for="UseEvents"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UseResetPassword">
|
||||
<label class="form-check-label" asp-for="UseResetPassword"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UseCustomPermissions">
|
||||
<label class="form-check-label" asp-for="UseCustomPermissions"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<h3>Password Manager</h3>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UseTotp">
|
||||
<label class="form-check-label" asp-for="UseTotp"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UsersGetPremium">
|
||||
<label class="form-check-label" asp-for="UsersGetPremium"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<h3>Secrets Manager</h3>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UseSecretsManager">
|
||||
<label class="form-check-label" asp-for="UseSecretsManager"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Licensing</h2>
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="LicenseKey"></label>
|
||||
<input type="text" class="form-control" asp-for="LicenseKey">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="ExpirationDate"></label>
|
||||
<input type="datetime-local" class="form-control" asp-for="ExpirationDate">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2>Billing</h2>
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="BillingEmail"></label>
|
||||
<input type="email" class="form-control" asp-for="BillingEmail">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<div class="form-group">
|
||||
<label asp-for="Gateway"></label>
|
||||
<select class="form-control" asp-for="Gateway"
|
||||
asp-items="Html.GetEnumSelectList<Bit.Core.Enums.GatewayType>()">
|
||||
<option value="">--</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="GatewayCustomerId"></label>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" asp-for="GatewayCustomerId">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-secondary" type="button" id="gateway-customer-link">
|
||||
<i class="fa fa-external-link"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="GatewaySubscriptionId"></label>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" asp-for="GatewaySubscriptionId">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-secondary" type="button" id="gateway-subscription-link">
|
||||
<i class="fa fa-external-link"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@await Html.PartialAsync("_OrganizationForm", Model)
|
||||
<div class="d-flex mt-4">
|
||||
<button type="submit" class="btn btn-primary" form="edit-form">Save</button>
|
||||
<div class="ml-auto d-flex">
|
||||
|
@ -6,6 +6,11 @@
|
||||
|
||||
<h1>Organization <small>@Model.Organization.Name</small></h1>
|
||||
|
||||
@if (Model.Provider != null)
|
||||
{
|
||||
<h2>Provider Relationship</h2>
|
||||
@await Html.PartialAsync("_ProviderInformation", Model.Provider)
|
||||
}
|
||||
<h2>Information</h2>
|
||||
@await Html.PartialAsync("_ViewInformation", Model)
|
||||
@if(GlobalSettings.SelfHosted)
|
||||
|
@ -0,0 +1,9 @@
|
||||
@using Bit.SharedWeb.Utilities
|
||||
@model Bit.Core.Entities.Provider.Provider
|
||||
<dl class="row">
|
||||
<dt class="col-sm-4 col-lg-3">Provider Name</dt>
|
||||
<dd class="col-sm-8 col-lg-9">@Model.Name</dd>
|
||||
|
||||
<dt class="col-sm-4 col-lg-3">Provider Type</dt>
|
||||
<dd class="col-sm-8 col-lg-9">@(Model.Type.GetDisplayAttribute()?.GetName())</dd>
|
||||
</dl>
|
97
src/Admin/Views/Providers/AddExistingOrganization.cshtml
Normal file
97
src/Admin/Views/Providers/AddExistingOrganization.cshtml
Normal file
@ -0,0 +1,97 @@
|
||||
@using Bit.SharedWeb.Utilities
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@model OrganizationUnassignedToProviderSearchViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Add Existing Organization";
|
||||
var providerId = ViewContext.RouteData.Values["id"];
|
||||
}
|
||||
|
||||
<h1>Add Existing Organization</h1>
|
||||
<div class="row mb-2">
|
||||
<div class="col">
|
||||
<form class="form-inline mb-2" method="get" asp-route-id="@providerId">
|
||||
<label class="sr-only" asp-for="OrganizationName"></label>
|
||||
<input type="text" class="form-control mb-2 mr-2 flex-fill" placeholder="@Html.DisplayNameFor(m => m.OrganizationName)" asp-for="OrganizationName" name="name">
|
||||
<label class="sr-only" asp-for="OrganizationOwnerEmail"></label>
|
||||
<input type="email" class="form-control mb-2 mr-2 flex-fill" placeholder="@Html.DisplayNameFor(m => m.OrganizationOwnerEmail)" asp-for="OrganizationOwnerEmail" name="ownerEmail">
|
||||
<button type="submit" class="btn btn-primary mb-2" title="Search" formmethod="get"><i class="fa fa-search"></i> Search</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="post" id="select-form" asp-route-id="@providerId">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 20px;">All</th>
|
||||
<th>Name</th>
|
||||
<th style="width: 190px;">Plan</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@if (!Model.Items.Any())
|
||||
{
|
||||
<tr>
|
||||
<td colspan="5">No results to list.</td>
|
||||
</tr>
|
||||
}
|
||||
else
|
||||
{
|
||||
@for (var i = 0; i < Model.Items.Count; i++)
|
||||
{
|
||||
<tr>
|
||||
<td class="text-center">
|
||||
@Html.HiddenFor(m => Model.Items[i].Id, new { @readonly = "readonly", autocomplete = "off" })
|
||||
@Html.CheckBoxFor(m => Model.Items[i].Selected)
|
||||
</td>
|
||||
<td>@Html.ActionLink(Model.Items[i].Name, "Edit", "Organizations", new { id = Model.Items[i].Id }, new { target = "_blank" })</td>
|
||||
<td>@(Model.Items[i].PlanType.GetDisplayAttribute()?.Name ?? Model.Items[i].PlanType.ToString())</td>
|
||||
</tr>
|
||||
}
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<nav>
|
||||
<ul class="pagination">
|
||||
@if (Model.PreviousPage.HasValue)
|
||||
{
|
||||
<li class="page-item">
|
||||
<a class="page-link" asp-action="AddExistingOrganization" asp-route-id="@providerId" asp-route-page="@Model.PreviousPage.Value"
|
||||
asp-route-count="@Model.Count" asp-route-ownerEmail="@Model.OrganizationOwnerEmail"
|
||||
asp-route-name="@Model.OrganizationName">Previous</a>
|
||||
</li>
|
||||
}
|
||||
else
|
||||
{
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#" tabindex="-1">Previous</a>
|
||||
</li>
|
||||
}
|
||||
@if (Model.NextPage.HasValue)
|
||||
{
|
||||
<li class="page-item">
|
||||
<a class="page-link" asp-action="AddExistingOrganization" asp-route-id="@providerId" asp-route-page="@Model.NextPage.Value"
|
||||
asp-route-count="@Model.Count" asp-route-ownerEmail="@Model.OrganizationOwnerEmail"
|
||||
asp-route-name="@Model.OrganizationName">Next</a>
|
||||
</li>
|
||||
}
|
||||
else
|
||||
{
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#" tabindex="-1">Next</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button type="submit" class="btn btn-primary" form="select-form">Add to Reseller</button>
|
||||
</div>
|
||||
</div>
|
@ -1,16 +1,55 @@
|
||||
@model CreateProviderModel
|
||||
@using Bit.SharedWeb.Utilities
|
||||
@model CreateProviderModel
|
||||
@{
|
||||
ViewData["Title"] = "Create Provider";
|
||||
}
|
||||
|
||||
@section Scripts {
|
||||
<script>
|
||||
function toggleProviderTypeInfo(value) {
|
||||
document.querySelectorAll('[id^="info-"]').forEach(el => { el.classList.add('d-none'); });
|
||||
document.getElementById('info-' + value).classList.remove('d-none');
|
||||
}
|
||||
</script>
|
||||
}
|
||||
|
||||
<h1>Create Provider</h1>
|
||||
|
||||
<form method="post">
|
||||
<div asp-validation-summary="All" class="alert alert-danger"></div>
|
||||
|
||||
<div class="form-group">
|
||||
<label asp-for="OwnerEmail"></label>
|
||||
<input type="text" class="form-control" asp-for="OwnerEmail">
|
||||
<label asp-for="Type" class="h2"></label>
|
||||
@foreach(ProviderType providerType in Enum.GetValues(typeof(ProviderType)))
|
||||
{
|
||||
var providerTypeValue = (int)providerType;
|
||||
<div class="form-check">
|
||||
@Html.RadioButtonFor(m => m.Type, providerType, new { id = $"providerType-{providerTypeValue}", @class = "form-check-input", onclick=$"toggleProviderTypeInfo({providerTypeValue})" })
|
||||
@Html.LabelFor(m => m.Type, providerType.GetDisplayAttribute()?.GetName(), new { @class = "form-check-label align-middle", @for = $"providerType-{providerTypeValue}" })
|
||||
<br/>
|
||||
@Html.LabelFor(m => m.Type, providerType.GetDisplayAttribute()?.GetDescription(), new { @class = "form-check-label small text-muted ml-3 align-top", @for = $"providerType-{providerTypeValue}" })
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div id="@($"info-{(int)ProviderType.Msp}")" class="form-group @(Model.Type != ProviderType.Msp ? "d-none" : string.Empty)">
|
||||
<h2>MSP Info</h2>
|
||||
<div class="form-group">
|
||||
<label asp-for="OwnerEmail"></label>
|
||||
<input type="text" class="form-control" asp-for="OwnerEmail">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="@($"info-{(int)ProviderType.Reseller}")" class="form-group @(Model.Type != ProviderType.Reseller ? "d-none" : string.Empty)">
|
||||
<h2>Reseller Info</h2>
|
||||
<div class="form-group">
|
||||
<label asp-for="BusinessName"></label>
|
||||
<input type="text" class="form-control" asp-for="BusinessName">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="BillingEmail"></label>
|
||||
<input type="text" class="form-control" asp-for="BillingEmail">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary mb-2">Create Provider</button>
|
||||
|
21
src/Admin/Views/Providers/CreateOrganization.cshtml
Normal file
21
src/Admin/Views/Providers/CreateOrganization.cshtml
Normal file
@ -0,0 +1,21 @@
|
||||
@model OrganizationEditModel
|
||||
@{
|
||||
ViewData["Title"] = "Create Client Organization";
|
||||
}
|
||||
|
||||
@section Scripts {
|
||||
@await Html.PartialAsync("_OrganizationFormScripts")
|
||||
}
|
||||
|
||||
<h1>New Client Organization</h1>
|
||||
|
||||
@await Html.PartialAsync("_OrganizationForm", Model)
|
||||
<div class="d-flex mt-4">
|
||||
<button type="submit" class="btn btn-primary" form="edit-form">Save</button>
|
||||
<div class="ml-auto d-flex">
|
||||
<form asp-controller="Providers" asp-action="Edit" asp-route-id="@Model.Provider.Id"
|
||||
onsubmit="return confirm('Are you sure you want to cancel?')">
|
||||
<button class="btn btn-outline-secondary" type="submit">Cancel</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
@ -36,6 +36,14 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="BillingPhone"></label>
|
||||
<input type="tel" class="form-control" asp-for="BillingPhone">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@await Html.PartialAsync("Organizations", Model)
|
||||
<div class="d-flex mt-4">
|
||||
|
@ -1,4 +1,5 @@
|
||||
@model ProvidersModel
|
||||
@using Bit.SharedWeb.Utilities
|
||||
@model ProvidersModel
|
||||
@{
|
||||
ViewData["Title"] = "Providers";
|
||||
}
|
||||
@ -25,6 +26,7 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th style="width: 190px;">Provider Type</th>
|
||||
<th style="width: 190px;">Status</th>
|
||||
<th style="width: 150px;">Created</th>
|
||||
</tr>
|
||||
@ -44,6 +46,7 @@
|
||||
<td>
|
||||
<a asp-action="@Model.Action" asp-route-id="@provider.Id">@(provider.Name ?? "Pending")</a>
|
||||
</td>
|
||||
<td>@provider.Type.GetDisplayAttribute()?.GetShortName()</td>
|
||||
<td>@provider.Status</td>
|
||||
<td>
|
||||
<span title="@provider.CreationDate.ToString()">
|
||||
|
@ -1,4 +1,7 @@
|
||||
@model ProviderViewModel
|
||||
|
||||
@await Html.PartialAsync("_ProviderScripts")
|
||||
|
||||
<h2>Provider Organizations</h2>
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
@ -6,7 +9,17 @@
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th style="width: 50%;">Name</th>
|
||||
<th style="width: 50%;">Status</th>
|
||||
<th>
|
||||
@if (Model.Provider.Type == ProviderType.Reseller)
|
||||
{
|
||||
<div class="float-right text-nowrap">
|
||||
<a asp-controller="Providers" asp-action="CreateOrganization" asp-route-providerId="@Model.Provider.Id" class="btn btn-sm btn-primary">New Organization</a>
|
||||
<a asp-controller="Providers" asp-action="AddExistingOrganization" asp-route-id="@Model.Provider.Id" class="btn btn-sm btn-outline-primary">Add Existing Organization</a>
|
||||
</div>
|
||||
}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -22,8 +35,24 @@
|
||||
{
|
||||
<tr>
|
||||
<td class="align-middle">
|
||||
<a asp-controller="Organizations" asp-action="Edit"
|
||||
asp-route-id="@org.OrganizationId">@org.OrganizationName</a>
|
||||
<a asp-controller="Organizations" asp-action="Edit" asp-route-id="@org.OrganizationId">@org.OrganizationName</a>
|
||||
</td>
|
||||
<td>
|
||||
@org.Status
|
||||
</td>
|
||||
<td>
|
||||
<div class="float-right">
|
||||
@if (org.Status == OrganizationStatusType.Pending)
|
||||
{
|
||||
<a href="#" class="float-right" onclick="return resendOwnerInvite('@org.OrganizationId', '@org.OrganizationName');">
|
||||
<i class="fa fa-envelope-o fa-lg" title="Resend Setup Invite"></i>
|
||||
</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<i class="fa fa-envelope-o fa-lg text-secondary"></i>
|
||||
}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
|
20
src/Admin/Views/Providers/_ProviderScripts.cshtml
Normal file
20
src/Admin/Views/Providers/_ProviderScripts.cshtml
Normal file
@ -0,0 +1,20 @@
|
||||
<script>
|
||||
function resendOwnerInvite(orgId, orgName) {
|
||||
if (confirm('Resend invite to "' + orgName + '"?')) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: '@Url.Action("ResendOwnerInvite", "Organizations")' + '?id=' + orgId,
|
||||
dataType: 'json',
|
||||
contentType: false,
|
||||
processData: false,
|
||||
success: function (response) {
|
||||
alert('Invitation has been resent!');
|
||||
},
|
||||
error: function (response) {
|
||||
alert("Error!");
|
||||
}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
</script>
|
@ -1,4 +1,5 @@
|
||||
@model ProviderViewModel
|
||||
@using Bit.SharedWeb.Utilities
|
||||
@model ProviderViewModel
|
||||
<dl class="row">
|
||||
<dt class="col-sm-4 col-lg-3">Id</dt>
|
||||
<dd class="col-sm-8 col-lg-9"><code>@Model.Provider.Id</code></dd>
|
||||
@ -7,7 +8,10 @@
|
||||
<dd class="col-sm-8 col-lg-9">@Model.Provider.Status</dd>
|
||||
|
||||
<dt class="col-sm-4 col-lg-3">Users</dt>
|
||||
<dd class="col-sm-8 col-lg-9">@Model.UserCount</dd>
|
||||
<dd class="col-sm-8 col-lg-9">@(Model.Provider.Type == ProviderType.Reseller ? "N/A" : Model.UserCount)</dd>
|
||||
|
||||
<dt class="col-sm-4 col-lg-3">Provider Type</dt>
|
||||
<dd class="col-sm-8 col-lg-9">@(Model.Provider.Type.GetDisplayAttribute()?.GetName())</dd>
|
||||
|
||||
<dt class="col-sm-4 col-lg-3">Created</dt>
|
||||
<dd class="col-sm-8 col-lg-9">@Model.Provider.CreationDate.ToString()</dd>
|
||||
|
247
src/Admin/Views/Shared/_OrganizationForm.cshtml
Normal file
247
src/Admin/Views/Shared/_OrganizationForm.cshtml
Normal file
@ -0,0 +1,247 @@
|
||||
@using Bit.SharedWeb.Utilities
|
||||
@model OrganizationEditModel
|
||||
|
||||
<form method="post" id="edit-form" asp-route-providerId="@Model.Provider?.Id">
|
||||
<input asp-for="SalesAssistedTrialStarted" type="hidden">
|
||||
<h2>General</h2>
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="Name"></label>
|
||||
<input type="text" class="form-control" asp-for="Name" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (Model.Provider?.Type == ProviderType.Reseller)
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label>Client Owner Email</label>
|
||||
@if (!string.IsNullOrWhiteSpace(Model.Owners))
|
||||
{
|
||||
<input type="text" class="form-control" asp-for="Owners" readonly="readonly">
|
||||
}
|
||||
else
|
||||
{
|
||||
<input type="text" class="form-control" asp-for="Owners" required>
|
||||
}
|
||||
<label class="form-check-label small text-muted align-top">This user should be independent of the Provider. If the Provider is disassociated with the organization, this user will maintain ownership of the organization.</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@if (Model.Organization != null)
|
||||
{
|
||||
<div class="form-check mb-3">
|
||||
<input type="checkbox" class="form-check-input" asp-for="Enabled">
|
||||
<label class="form-check-label" asp-for="Enabled"></label>
|
||||
</div>
|
||||
}
|
||||
<h2>Business Information</h2>
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="BusinessName"></label>
|
||||
<input type="text" class="form-control" asp-for="BusinessName">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2>Plan</h2>
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="PlanType"></label>
|
||||
@{
|
||||
var planTypes = Enum.GetValues<PlanType>()
|
||||
.Where(p => Model.Provider == null || p is >= PlanType.TeamsMonthly and <= PlanType.EnterpriseAnnually)
|
||||
.Select(e => new SelectListItem
|
||||
{
|
||||
Value = ((int)e).ToString(),
|
||||
Text = e.GetDisplayAttribute()?.GetName() ?? e.ToString()
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
<select class="form-control" asp-for="PlanType" asp-items="planTypes"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="Plan"></label>
|
||||
<input type="text" class="form-control" asp-for="Plan" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="Seats"></label>
|
||||
<input type="number" class="form-control" asp-for="Seats" min="1">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="MaxCollections"></label>
|
||||
<input type="number" class="form-control" asp-for="MaxCollections" min="1">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="MaxStorageGb"></label>
|
||||
<input type="number" class="form-control" asp-for="MaxStorageGb" min="1">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">
|
||||
<div class="form-group">
|
||||
<label asp-for="MaxAutoscaleSeats"></label>
|
||||
<input type="number" class="form-control" asp-for="MaxAutoscaleSeats" min="1">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2>Features</h2>
|
||||
<div class="row mb-3">
|
||||
<div class="col-4">
|
||||
<h3>General</h3>
|
||||
<div class="form-check mb-2">
|
||||
<input type="checkbox" class="form-check-input" asp-for="SelfHost">
|
||||
<label class="form-check-label" asp-for="SelfHost"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="Use2fa">
|
||||
<label class="form-check-label" asp-for="Use2fa"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UseApi">
|
||||
<label class="form-check-label" asp-for="UseApi"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UseGroups">
|
||||
<label class="form-check-label" asp-for="UseGroups"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UsePolicies">
|
||||
<label class="form-check-label" asp-for="UsePolicies"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UseSso">
|
||||
<label class="form-check-label" asp-for="UseSso"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UseKeyConnector">
|
||||
<label class="form-check-label" asp-for="UseKeyConnector"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UseScim">
|
||||
<label class="form-check-label" asp-for="UseScim"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UseDirectory">
|
||||
<label class="form-check-label" asp-for="UseDirectory"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UseEvents">
|
||||
<label class="form-check-label" asp-for="UseEvents"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UseResetPassword">
|
||||
<label class="form-check-label" asp-for="UseResetPassword"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UseCustomPermissions">
|
||||
<label class="form-check-label" asp-for="UseCustomPermissions"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<h3>Password Manager</h3>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UseTotp">
|
||||
<label class="form-check-label" asp-for="UseTotp"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UsersGetPremium">
|
||||
<label class="form-check-label" asp-for="UsersGetPremium"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<h3>Secrets Manager</h3>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" asp-for="UseSecretsManager">
|
||||
<label class="form-check-label" asp-for="UseSecretsManager"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Licensing</h2>
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="LicenseKey"></label>
|
||||
<input type="text" class="form-control" asp-for="LicenseKey">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="ExpirationDate"></label>
|
||||
<input type="datetime-local" class="form-control" asp-for="ExpirationDate">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2>Billing</h2>
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="BillingEmail"></label>
|
||||
@if (Model.Provider?.Type == ProviderType.Reseller)
|
||||
{
|
||||
<input type="email" class="form-control" asp-for="BillingEmail" readonly="readonly">
|
||||
}
|
||||
else
|
||||
{
|
||||
<input type="email" class="form-control" asp-for="BillingEmail">
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<div class="form-group">
|
||||
<label asp-for="Gateway"></label>
|
||||
<select class="form-control" asp-for="Gateway"
|
||||
asp-items="Html.GetEnumSelectList<Bit.Core.Enums.GatewayType>()">
|
||||
<option value="">--</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="GatewayCustomerId"></label>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" asp-for="GatewayCustomerId">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-secondary" type="button" id="gateway-customer-link">
|
||||
<i class="fa fa-external-link"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="GatewaySubscriptionId"></label>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" asp-for="GatewaySubscriptionId">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-secondary" type="button" id="gateway-subscription-link">
|
||||
<i class="fa fa-external-link"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
35
src/Admin/Views/Shared/_OrganizationFormScripts.cshtml
Normal file
35
src/Admin/Views/Shared/_OrganizationFormScripts.cshtml
Normal file
@ -0,0 +1,35 @@
|
||||
<script>
|
||||
(() => {
|
||||
document.getElementById('@(nameof(Model.PlanType))').addEventListener('change', () => {
|
||||
const selectEl = document.getElementById('@(nameof(Model.PlanType))');
|
||||
const selectText = selectEl.options[selectEl.selectedIndex].text;
|
||||
document.getElementById('@(nameof(Model.Plan))').value = selectText;
|
||||
});
|
||||
document.getElementById('gateway-customer-link').addEventListener('click', () => {
|
||||
const gateway = document.getElementById('@(nameof(Model.Gateway))');
|
||||
const customerId = document.getElementById('@(nameof(Model.GatewayCustomerId))');
|
||||
if (!gateway || gateway.value === '' || !customerId || customerId.value === '') {
|
||||
return;
|
||||
}
|
||||
if (gateway.value === '@((byte)Bit.Core.Enums.GatewayType.Stripe)') {
|
||||
window.open('https://dashboard.stripe.com/customers/' + customerId.value, '_blank');
|
||||
} else if (gateway.value === '@((byte)Bit.Core.Enums.GatewayType.Braintree)') {
|
||||
window.open('https://www.braintreegateway.com/merchants/@(Model.BraintreeMerchantId)/'
|
||||
+ customerId.value, '_blank');
|
||||
}
|
||||
});
|
||||
document.getElementById('gateway-subscription-link').addEventListener('click', () => {
|
||||
const gateway = document.getElementById('@(nameof(Model.Gateway))');
|
||||
const subId = document.getElementById('@(nameof(Model.GatewaySubscriptionId))');
|
||||
if (!gateway || gateway.value === '' || !subId || subId.value === '') {
|
||||
return;
|
||||
}
|
||||
if (gateway.value === '@((byte)Bit.Core.Enums.GatewayType.Stripe)') {
|
||||
window.open('https://dashboard.stripe.com/subscriptions/' + subId.value, '_blank');
|
||||
} else if (gateway.value === '@((byte)Bit.Core.Enums.GatewayType.Braintree)') {
|
||||
window.open('https://www.braintreegateway.com/merchants/@(Model.BraintreeMerchantId)/' +
|
||||
'subscriptions/' + subId.value, '_blank');
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
Reference in New Issue
Block a user