Added Viewer and

change to App Setting File from Constants
This commit is contained in:
Mike Phares 2022-07-27 10:47:57 -07:00
parent 2afec95704
commit b155863645
1012 changed files with 53014 additions and 110896 deletions

47
.groovy
View File

@ -4,7 +4,6 @@ import groovy.transform.Field
@Field String _DDrive = 'D:/'
@Field String _ExePath = '...'
@Field String _AgentStaging = ''
@Field String _NGINXFile = '...'
@Field String _PortNumber = '...'
@Field String _AssemblyName = '...'
@ -14,10 +13,10 @@ import groovy.transform.Field
@Field String _TargetLocation = '...'
@Field String _FirstBeforePlus = '5000'
@Field String _GitName = 'OI-Metrology'
@Field String _ProjectDirectory = 'Archive'
@Field String _MonARessource = 'OI_Metrology'
@Field String _WorkingDirectoryName = 'IFXApps'
@Field String _DDriveNet = "${_DDrive}${_NetVersion}"
@Field String _AgentStaging = 'messa010ec-ecfisysadmin'
@Field String _AgentProduction = 'messa010ec-ecfisysadmin'
@Field String _CredentialsId = 'Metrology-Username-Password'
@Field String _Company = 'Infineon Technologies Americas Corp.'
@ -31,6 +30,7 @@ pipeline {
string(name: 'MONA_SUFFIX', defaultValue: env.JENKINS_ENVIRONMENT == 'Development' ? '_IFX' : '_EC', description: 'MonA Suffix')
string(name: 'GIT_SERVER', defaultValue: env.JENKINS_ENVIRONMENT == 'Development' ? 'mestsa003.infineon.com' : 'mestsa07ec.ec.local', description: 'git server')
string(name: 'DEFAULT_FILE_SERVER', defaultValue: env.JENKINS_ENVIRONMENT == 'Development' ? 'messv02ecc1_ec_local' : 'messv02ecc1.ec.local', description: 'Default file server...')
string(name: 'PROJECT_DIRECTORY', defaultValue: 'Archive', description: 'Archive|Viewer')
}
stages {
stage('Git') {
@ -43,10 +43,10 @@ pipeline {
stage('Setup') {
steps {
script {
_AssemblyName = "${env.JOB_NAME}"
_AssemblyName = "${env.JOB_NAME}-${env.PROJECT_DIRECTORY}"
_GitCommitSeven = '1234567'
// _GitCommitSeven = env.GIT_COMMIT.substring(0, 7)
dir(_ProjectDirectory) {
dir(env.PROJECT_DIRECTORY) {
def files = findFiles(glob: '*.csproj')
if (files.length != 1) {
error("Build failed because couldn't find a *.csproj file")
@ -85,7 +85,7 @@ pipeline {
else {
_PortNumber = (segments[2].toInteger() + 2).toString()
}
_ExePath = "${_DDriveNet}/${_GitCommitSeven}-${env.BUILD_NUMBER}-${_PortNumber}-${env.JOB_NAME}/${_AssemblyName}.exe"
_ExePath = "${_DDriveNet}/${_GitCommitSeven}-${env.BUILD_NUMBER}-${_PortNumber}-${env.JOB_NAME}-${env.PROJECT_DIRECTORY}/${_AssemblyName}.exe"
}
}
}
@ -111,6 +111,7 @@ pipeline {
echo "JENKINS_ENVIRONMENT ${env.JENKINS_ENVIRONMENT}" // 11
echo "JENKINS_URL ${env.JENKINS_URL}" // http://localhost:8080/
echo "JOB_NAME ${env.JOB_NAME}" // ...
echo "PROJECT_DIRECTORY ${env.PROJECT_DIRECTORY}" // ...
echo "WORKSPACE ${env.WORKSPACE}" // D:\.jenkins\_\...
}
}
@ -122,7 +123,7 @@ pipeline {
stage('Safe storage of app secrets') {
steps {
withCredentials([usernamePassword(credentialsId: _CredentialsId, passwordVariable: 'password', usernameVariable: 'username')]) {
dir(_ProjectDirectory) {
dir(env.PROJECT_DIRECTORY) {
bat(returnStatus: true, script: '"' + _ProgramFilesDotnet + '" ' +
'user-secrets init')
bat(returnStatus: true, script: '"' + _ProgramFilesDotnet + '" ' +
@ -140,7 +141,7 @@ pipeline {
bat(returnStatus: true, script: '"' + _ProgramFilesDotnet + '" ' +
'user-secrets set "WorkingDirectoryName" "' + _WorkingDirectoryName + '"')
bat(returnStatus: true, script: '"' + _ProgramFilesDotnet + '" ' +
'user-secrets set "MonARessource" "' + _MonARessource + env.MONA_SUFFIX + '"')
'user-secrets set "MonARessource" "' + _MonARessource + '_' + env.PROJECT_DIRECTORY + env.MONA_SUFFIX + '"')
}
}
}
@ -148,7 +149,7 @@ pipeline {
// stage('Core Build (packagemanagement.eu.infineon.com)') {
// steps {
// echo "Build number is ${currentBuild.number}"
// dir(_ProjectDirectory) {
// dir(env.PROJECT_DIRECTORY) {
// bat(returnStatus: true, script: '"' + _ProgramFilesDotnet + '" ' +
// 'build --runtime win-x64 --self-contained --verbosity quiet --source ' +
// 'https://packagemanagement.eu.infineon.com:4430/api/v2/')
@ -158,7 +159,7 @@ pipeline {
stage('Core Build') {
steps {
echo "Build number is ${currentBuild.number}"
dir(_ProjectDirectory) {
dir(env.PROJECT_DIRECTORY) {
bat(returnStatus: true, script: '"' + _ProgramFilesDotnet + '" ' +
'build --runtime win-x64 --self-contained --verbosity quiet')
}
@ -166,7 +167,7 @@ pipeline {
}
stage('Commit Id') {
steps {
dir(_ProjectDirectory) {
dir(env.PROJECT_DIRECTORY) {
writeFile(file: 'bin/Debug/' + _NetVersion + "/win-x64/${env.GIT_COMMIT}-${env.BUILD_NUMBER}.txt", text: "${env.GIT_URL}")
}
}
@ -176,7 +177,7 @@ pipeline {
// timeout(time: 10, unit: 'MINUTES')
// }
// steps {
// dir(_ProjectDirectory) {
// dir(env.PROJECT_DIRECTORY) {
// bat('dotnet --info')
// }
// }
@ -188,32 +189,30 @@ pipeline {
// }
stage('Package') {
steps {
dir(_ProjectDirectory) {
fileOperations([fileZipOperation(folderPath: 'bin/Debug/' + _NetVersion + '/win-x64', outputFolderPath: "${_DDriveNet}/${_GitCommitSeven}-${env.BUILD_NUMBER}-${_PortNumber}-${env.JOB_NAME}-Debug")])
fileOperations([fileCopyOperation(excludes: '', flattenFiles: true, includes: "${_AssemblyName}*", renameFiles: false, sourceCaptureExpression: '', targetLocation: "${_DDriveNet}/${_GitCommitSeven}-${env.BUILD_NUMBER}-${_PortNumber}-${env.JOB_NAME}-Debug", targetNameExpression: '')])
dir(env.PROJECT_DIRECTORY) {
fileOperations([fileZipOperation(folderPath: 'bin/Debug/' + _NetVersion + '/win-x64', outputFolderPath: "${_DDriveNet}/${_GitCommitSeven}-${env.BUILD_NUMBER}-${_PortNumber}-${env.JOB_NAME}-${env.PROJECT_DIRECTORY}-Debug")])
fileOperations([fileCopyOperation(excludes: '', flattenFiles: true, includes: "${_AssemblyName}*", renameFiles: false, sourceCaptureExpression: '', targetLocation: "${_DDriveNet}/${_GitCommitSeven}-${env.BUILD_NUMBER}-${_PortNumber}-${env.JOB_NAME}-${env.PROJECT_DIRECTORY}-Debug", targetNameExpression: '')])
}
}
}
stage('Publish') {
steps {
dir(_ProjectDirectory) {
bat(returnStatus: true, script: '"' + _ProgramFilesDotnet + '" ' +
'remove reference "../Client/' + env.JOB_NAME + '.Client.csproj"')
dir(env.PROJECT_DIRECTORY) {
bat(returnStatus: true, script: '"' + _ProgramFilesDotnet + '" ' +
'publish --configuration Release --runtime win-x64 --verbosity quiet ' +
"--self-contained true --p:Version=6.0.202-${_GitCommitSeven}-${env.BUILD_NUMBER} -o " +
'"' + "${_DDriveNet}/${_GitCommitSeven}-${env.BUILD_NUMBER}-${_PortNumber}-${env.JOB_NAME}" + '"')
'"' + "${_DDriveNet}/${_GitCommitSeven}-${env.BUILD_NUMBER}-${_PortNumber}-${env.JOB_NAME}-${env.PROJECT_DIRECTORY}" + '"')
}
}
}
stage('Service') {
steps {
withCredentials([usernamePassword(credentialsId: _CredentialsId, passwordVariable: 'password', usernameVariable: 'username')]) {
bat(returnStatus: true, script: 'sc create "' + "${env.JOB_NAME}-${_PortNumber}" + '" ' +
'start= delayed-auto DisplayName="' + "${env.JOB_NAME}-${_PortNumber}" + '" ' +
bat(returnStatus: true, script: 'sc create "' + "${env.JOB_NAME}-${env.PROJECT_DIRECTORY}-${_PortNumber}" + '" ' +
'start= delayed-auto DisplayName="' + "${env.JOB_NAME}-${env.PROJECT_DIRECTORY}-${_PortNumber}" + '" ' +
'binPath= "' + _ExePath + '" ' +
'obj= "' + "${env.USERDOMAIN}\\${username}" + '" password= "' + password + '"')
bat(returnStatus: true, script: 'sc start "' + "${env.JOB_NAME}-${_PortNumber}" + '"')
bat(returnStatus: true, script: 'sc start "' + "${env.JOB_NAME}-${env.PROJECT_DIRECTORY}-${_PortNumber}" + '"')
}
}
}
@ -244,7 +243,7 @@ pipeline {
// }
// stage('Copy Files to: file-share') {
// steps {
// dir(_ProjectDirectory + '/bin/Debug/' + _NetVersion + '/win-x64') {
// dir(env.PROJECT_DIRECTORY + '/bin/Debug/' + _NetVersion + '/win-x64') {
// fileOperations([fileCopyOperation(excludes: '', flattenFiles: true, includes: "${_AssemblyName}*.txt", renameFiles: false, sourceCaptureExpression: '', targetLocation: _TargetLocation, targetNameExpression: '')])
// fileOperations([fileCopyOperation(excludes: '', flattenFiles: true, includes: "${_AssemblyName}*.dll", renameFiles: false, sourceCaptureExpression: '', targetLocation: _TargetLocation, targetNameExpression: '')])
// fileOperations([fileCopyOperation(excludes: '', flattenFiles: true, includes: "${_AssemblyName}*.exe", renameFiles: false, sourceCaptureExpression: '', targetLocation: _TargetLocation, targetNameExpression: '')])
@ -255,10 +254,10 @@ pipeline {
}
post {
always {
dir(_ProjectDirectory + '/bin') {
dir(env.PROJECT_DIRECTORY + '/bin') {
deleteDir()
}
dir(_ProjectDirectory + '/obj') {
dir(env.PROJECT_DIRECTORY + '/obj') {
deleteDir()
}
// cleanWs()

View File

@ -29,7 +29,8 @@
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
"request": "attach",
"processName": "Archive"
}
]
}

View File

@ -8,8 +8,8 @@ using System.IO;
namespace OI.Metrology.Archive.ApiControllers;
public class AttachmentsController : Controller
{
protected IMetrologyRepo _Repo;
protected IAttachmentsService _AttachmentsService;
private readonly IMetrologyRepo _Repo;
private readonly IAttachmentsService _AttachmentsService;
public AttachmentsController(IMetrologyRepo repo, IAttachmentsService attachmentsService)
{

View File

@ -9,7 +9,7 @@ using System.Text.Json;
public class AwaitingDispoController : Controller
{
protected IMetrologyRepo _Repo;
private readonly IMetrologyRepo _Repo;
public AwaitingDispoController(IMetrologyRepo repo) => _Repo = repo;

View File

@ -1,8 +1,8 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using OI.Metrology.Archive.Models;
using OI.Metrology.Shared.DataModels;
using OI.Metrology.Shared.Repositories;
using OI.Metrology.Shared.Services;
@ -15,20 +15,19 @@ namespace OI.Metrology.Archive.ApiContollers;
[ApiController]
public class InboundController : ControllerBase
{
private IConfiguration Config { get; }
private ILogger Logger { get; }
private readonly ILogger _Logger;
private readonly IMetrologyRepo _Repo;
private readonly AppSettings _AppSettings;
private readonly IAttachmentsService _AttachmentService;
private readonly IInboundDataService _InboundDataService;
protected IMetrologyRepo _Repo;
protected IAttachmentsService _AttachmentService;
protected IInboundDataService _InboundDataService;
public InboundController(IConfiguration config, ILogger<InboundController> logger, IMetrologyRepo repo, IInboundDataService inboundDataService, IAttachmentsService attachmentService)
public InboundController(AppSettings appSettings, ILogger<InboundController> logger, IMetrologyRepo repo, IInboundDataService inboundDataService, IAttachmentsService attachmentService)
{
Config = config;
Logger = logger;
_Repo = repo;
_InboundDataService = inboundDataService;
_Logger = logger;
_AppSettings = appSettings;
_AttachmentService = attachmentService;
_InboundDataService = inboundDataService;
}
// this class represents the API response back to the client
@ -57,7 +56,7 @@ public class InboundController : ControllerBase
if (!IsIPAddressAllowed())
{
Logger.LogInformation($"Rejected remote IP: {HttpContext.Connection.RemoteIpAddress}");
_Logger.LogInformation($"Rejected remote IP: {HttpContext.Connection.RemoteIpAddress}");
r.Errors.Add("Remote IP is not on allowed list");
return Unauthorized(r);
}
@ -115,7 +114,7 @@ public class InboundController : ControllerBase
{
if (!IsIPAddressAllowed())
{
Logger.LogInformation($"Rejected remote IP: {HttpContext.Connection.RemoteIpAddress}");
_Logger.LogInformation($"Rejected remote IP: {HttpContext.Connection.RemoteIpAddress}");
return Unauthorized("Remote IP is not on allowed list");
}
@ -145,14 +144,13 @@ public class InboundController : ControllerBase
protected bool IsIPAddressAllowed()
{
string allowedList = Config[Constants.InboundApiAllowedIPList];
if (string.IsNullOrWhiteSpace(allowedList))
if (string.IsNullOrWhiteSpace(_AppSettings.InboundApiAllowedIPList))
return true;
System.Net.IPAddress remoteIP = HttpContext.Connection.RemoteIpAddress;
byte[] remoteIPBytes = remoteIP.GetAddressBytes();
string[] allowedIPs = allowedList.Split(';');
string[] allowedIPs = _AppSettings.InboundApiAllowedIPList.Split(';');
foreach (string ip in allowedIPs)
{
System.Net.IPAddress parsedIP;

View File

@ -1,5 +1,4 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using System;
using System.IO;
@ -7,6 +6,7 @@ using System.Linq;
namespace OI.Metrology.Archive.ApiContollers;
using OI.Metrology.Archive.Models;
using OI.Metrology.Shared.DataModels;
using OI.Metrology.Shared.Repositories;
using OI.Metrology.Shared.Services;
@ -21,15 +21,14 @@ public class ToolTypesController : Controller
// it is named after the /api/tooltypes prefix
// the URL pattern is RESTful and the tool type is the root of every request
private IConfiguration Config { get; }
private readonly IMetrologyRepo _Repo;
private readonly AppSettings _AppSettings;
private readonly IAttachmentsService _AttachmentsService;
protected IMetrologyRepo _Repo;
protected IAttachmentsService _AttachmentsService;
public ToolTypesController(IConfiguration config, IMetrologyRepo repo, IAttachmentsService attachmentsService)
public ToolTypesController(AppSettings appSettings, IMetrologyRepo repo, IAttachmentsService attachmentsService)
{
Config = config;
_Repo = repo;
_AppSettings = appSettings;
_AttachmentsService = attachmentsService;
}
@ -67,7 +66,7 @@ public class ToolTypesController : Controller
};
return Json(r, new JsonSerializerOptions { PropertyNamingPolicy = null, WriteIndented = true });
}
//Just Changed here
// Just Changed here
// Gets headers, request/response format is to allow paging with igniteUI
// The headerid parameter is used for navigating directly to a header, when the button is clicked in Awaiting Dispo
[HttpGet("/api/tooltypes/{id}/headers")]
@ -77,11 +76,11 @@ public class ToolTypesController : Controller
[FromQuery] DateTime? dateend,
[FromQuery] int? page,
[FromQuery] int? pagesize,
[FromQuery] long? headerid, bool isSharePoint)
[FromQuery] long? headerid)
{
long totalRecs;
System.Data.DataTable dt = _Repo.GetHeaders(id, datebegin, dateend, page, pagesize, headerid, out totalRecs, isSharePoint);
System.Data.DataTable dt = _Repo.GetHeaders(id, datebegin, dateend, page, pagesize, headerid, out totalRecs);
var r = new
{
@ -98,11 +97,11 @@ public class ToolTypesController : Controller
public IActionResult GetHeaderTitles(
int id,
[FromQuery] int? page,
[FromQuery] int? pagesize, bool isArchive)
[FromQuery] int? pagesize)
{
long totalRecs;
IEnumerable<HeaderCommon> dt = _Repo.GetHeaderTitles(id, page, pagesize, out totalRecs, isArchive);
IEnumerable<HeaderCommon> dt = _Repo.GetHeaderTitles(id, page, pagesize, out totalRecs);
var r = new
{
@ -118,11 +117,11 @@ public class ToolTypesController : Controller
[HttpGet("/api/tooltypes/{id}/headers/{headerid}/fields")]
public IActionResult GetHeaderFields(
int id,
long headerid, bool isArchive)
long headerid)
{
var r = new
{
Results = _Repo.GetHeaderFields(id, headerid, isArchive).Select(x => new { Column = x.Key, x.Value }).ToList()
Results = _Repo.GetHeaderFields(id, headerid).Select(x => new { Column = x.Key, x.Value }).ToList()
};
string json = JsonConvert.SerializeObject(r);
@ -148,12 +147,12 @@ public class ToolTypesController : Controller
[HttpGet("/api/tooltypes/{id}/headers/{headerid}/data")]
public IActionResult GetData(
int id,
long headerid, bool isSharePoint)
long headerid)
{
var r = new
{
Results = _Repo.GetData(id, headerid, isSharePoint)
Results = _Repo.GetData(id, headerid)
};
string json = JsonConvert.SerializeObject(r);
@ -166,7 +165,7 @@ public class ToolTypesController : Controller
int toolTypeId,
string tabletype,
string attachmentId,
string filename, bool isArchive)
string filename)
{
ToolType tt = _Repo.GetToolTypeByID(toolTypeId);
@ -177,8 +176,6 @@ public class ToolTypesController : Controller
if (!Guid.TryParse(attachmentId, out attachmentIdParsed))
return Content("Invalid attachment id");
//try
// {
// figure out what content type to use. this is very simple because there are only two types being used
string contenttype = "application/pdf";
if (filename.ToLower().TrimEnd().EndsWith(".txt"))
@ -186,18 +183,7 @@ public class ToolTypesController : Controller
// Get attachment stream and feed it to the client
Stream fs = _AttachmentsService.GetAttachmentStreamByAttachmentId(tt, header, attachmentIdParsed, filename);
/*if (isArchive)
{
fs = attachmentsService.GetAttachmentStreamByAttachmentIdArchive(tt, header, attachmentIdParsed, filename);
//fs = attachmentsService.GetAttachmentStreamByAttachmentId
}*/
return File(fs, contenttype);
//}
/*catch (Exception ex)
{
return Content(ex.Message);
}*/
}
// This endpoint triggers writing of the OI Export file
@ -247,13 +233,9 @@ public class ToolTypesController : Controller
// The output file will only have one line, the header columns are output first
// Then each detail rows has it's columns appended
// H1, H2, H3, D1.1, D1.2, D1.3, D2.1, D2.2, D2.3, etc
// Get the configured export path
string exportRootPath = Config[Constants.OIExportPathKey];
// Write the file
System.IO.File.WriteAllText(
Path.Join(exportRootPath, filename),
Path.Join(_AppSettings.OIExportPath, filename),
sb.ToString());
}

View File

@ -1,6 +1,6 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using OI.Metrology.Archive.Models;
using System;
using System.IO;
using System.Linq;
@ -12,13 +12,13 @@ namespace OI.Metrology.Archive;
// You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project
public class ApiLoggingMiddleware
{
private IConfiguration Config { get; }
private readonly RequestDelegate _Next;
private readonly AppSettings _AppSettings;
public ApiLoggingMiddleware(RequestDelegate next, IConfiguration config)
public ApiLoggingMiddleware(RequestDelegate next, AppSettings appSettings)
{
Config = config;
_Next = next;
_AppSettings = appSettings;
}
// this is the method called in ASP.NET Core middleware to handle an HTTP request
@ -29,25 +29,22 @@ public class ApiLoggingMiddleware
try
{
bool doLogging = false;
string pathsToLog = Config[Constants.ApiLoggingPathPrefixes];
string contentTypesToLog = Config[Constants.ApiLoggingContentTypes];
// check to see if this is a request path that is enabled for logging
if (!string.IsNullOrWhiteSpace(pathsToLog))
if (!string.IsNullOrWhiteSpace(_AppSettings.ApiLoggingPathPrefixes))
{
// check if the request path begins with any part of pathsToLog
if (pathsToLog.Split(';').Any(p => httpContext.Request.Path.StartsWithSegments(new PathString(p))))
if (_AppSettings.ApiLoggingPathPrefixes.Split(';').Any(p => httpContext.Request.Path.StartsWithSegments(new PathString(p))))
{
if (!string.IsNullOrWhiteSpace(contentTypesToLog))
{
// if there are content type filters configured, only log is the request begins with one of them
doLogging = contentTypesToLog.Split(';').Any(ct => httpContext.Request.ContentType.StartsWith(ct));
}
else
if (string.IsNullOrWhiteSpace(_AppSettings.ApiLoggingContentTypes))
{
// if no content type filter is defined, log all content types
doLogging = true;
}
else
{
// if there are content type filters configured, only log is the request begins with one of them
doLogging = _AppSettings.ApiLoggingContentTypes.Split(';').Any(ct => httpContext.Request.ContentType.StartsWith(ct));
}
}
}
@ -107,15 +104,14 @@ public class ApiLoggingMiddleware
{
int threadId = Environment.CurrentManagedThreadId;
string logPath = Config[Constants.ApiLogPath];
string fileName = $"ApiLog{requestTime:yyyyMMdd_hhmmssttt}_{threadId}.txt";
HttpContext context = request.HttpContext;
if (!Directory.Exists(logPath))
_ = Directory.CreateDirectory(logPath);
if (!Directory.Exists(_AppSettings.ApiLogPath))
_ = Directory.CreateDirectory(_AppSettings.ApiLogPath);
using StreamWriter sw = new(Path.Join(logPath, fileName), true);
using StreamWriter sw = new(Path.Join(_AppSettings.ApiLogPath, fileName), true);
sw.WriteLine($"Request at {requestTime:yyyy/MM/dd hh:mm:ss.ttt} from {context.Connection.RemoteIpAddress}");
sw.WriteLine($"{request.Method} {request.Path} {request.QueryString}");
sw.WriteLine("Request body:");

View File

@ -34,7 +34,14 @@
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.1.175" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Serilog.AspNetCore" Version="5.0.0" />
<PackageReference Include="Serilog.AspNetCore.Ingestion" Version="1.0.0-dev-00021" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.3.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Data.SqlClient" Version="4.8.3" />

View File

@ -1,13 +0,0 @@
namespace OI.Metrology.Archive;
public static class Constants
{
public const string ConnStringName = "SQL";
public const string ConnStringName2 = "SQL2";
public const string AttachmentPathKey = "AttachmentPath";
public const string OIExportPathKey = "OIExportPath";
public const string InboundApiAllowedIPList = "InboundApiAllowedIPList";
public const string ApiLoggingPathPrefixes = "ApiLoggingPathPrefixes";
public const string ApiLoggingContentTypes = "ApiLoggingContentTypes";
public const string ApiLogPath = "ApiLogPath";
}

View File

@ -8,9 +8,9 @@ namespace OI.Metrology.Archive.Controllers;
[Route("/error")]
public class ErrorHandlerController : Controller
{
private ILogger Logger { get; }
private readonly ILogger _Logger;
public ErrorHandlerController(ILogger<ErrorHandlerController> logger) => Logger = logger;
public ErrorHandlerController(ILogger<ErrorHandlerController> logger) => _Logger = logger;
public IActionResult Index()
{
@ -21,7 +21,7 @@ public class ErrorHandlerController : Controller
}
else
{
Logger.LogError("Unhandled exception: " + error.Error.ToString());
_Logger.LogError("Unhandled exception: " + error.Error.ToString());
dynamic r = new
{
Message = error.Error == null ? "Error" : error.Error.Message

View File

@ -1,5 +1,7 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using OI.Metrology.Archive.Models;
using OI.Metrology.Shared.DataModels;
using OI.Metrology.Shared.Repositories;
using OI.Metrology.Shared.ViewModels;
@ -12,35 +14,33 @@ namespace OI.Metrology.Archive.Controllers;
public class ExportController : Controller
{
private ILogger Logger { get; }
private readonly ILogger _Logger;
private readonly bool _IsTestDatabase;
private readonly IMetrologyRepo _Repo;
protected IMetrologyRepo _Repo;
public ExportController(ILogger<ExportController> logger, IMetrologyRepo repo)
public ExportController(AppSettings appSettings, ILogger<ExportController> logger, IMetrologyRepo repo)
{
Logger = logger;
_Repo = repo;
_Logger = logger;
_IsTestDatabase = appSettings.ConnectionString.Contains("test", StringComparison.InvariantCultureIgnoreCase);
}
protected static void LoadToolTypes(Export m, IEnumerable<ToolType> toolTypes)
public override void OnActionExecuted(ActionExecutedContext context)
{
m.ToolTypes = toolTypes
.Where(tt => tt.ExportSPName != null)
.Select(tt => new Shared.Models.SelectListItem(tt.ToolTypeName, tt.ID.ToString())).ToList();
base.OnActionExecuted(context);
ViewBag.IsTestDatabase = _IsTestDatabase;
}
[HttpGet]
[Route("/Export")]
public ActionResult Index()
{
Export model = new();
LoadToolTypes(model, _Repo.GetToolTypes());
model.ToolType = "";
model.StartTime = DateTime.Now.AddMonths(-1);
model.EndTime = DateTime.Now;
Export model = new()
{
ToolType = "",
StartTime = DateTime.Now.AddMonths(-1),
EndTime = DateTime.Now
};
return View(model);
}
@ -48,19 +48,20 @@ public class ExportController : Controller
[Route("/ExportData")]
public ActionResult ExportData(Export model)
{
ToolType toolType = null;
if (string.IsNullOrEmpty(model.ToolType))
ModelState.AddModelError("Exception", "Invalid selection");
else
{
if (model.StartTime > model.EndTime)
ModelState.AddModelError("EndTime", "End time must be after start time");
IEnumerable<ToolType> toolTypes = _Repo.GetToolTypes();
// is tooltype valid
ToolType toolType = toolTypes.Where(tt => tt.ID.ToString() == model.ToolType).SingleOrDefault();
if (toolType == null)
toolType = toolTypes.Where(tt => tt.ID.ToString() == model.ToolType).SingleOrDefault();
if (toolType is null)
ModelState.AddModelError("ToolType", "Invalid selection");
else if (string.IsNullOrWhiteSpace(toolType.ExportSPName))
ModelState.AddModelError("ToolType", "Tool type is not exportable");
// is enddate after startdate
if (model.StartTime > model.EndTime)
ModelState.AddModelError("EndTime", "End time must be after start time");
}
if (ModelState.IsValid)
{
try
@ -72,19 +73,16 @@ public class ExportController : Controller
}
catch (Exception ex)
{
ModelState.AddModelError("", "Error exporting data");
ModelState.AddModelError("", ex.Message);
ModelState.AddModelError("Exception", "Error exporting data");
ModelState.AddModelError("Exception", ex.Message);
string errorMessage = $"Error exporting: {ex}";
Logger.LogError(message: errorMessage);
_Logger.LogError(message: errorMessage);
}
}
LoadToolTypes(model, toolTypes);
return View("Index", model);
}
protected ActionResult DoCSVExport(String toolTypeName, string spName, DateTime startTime, DateTime endTime)
protected ActionResult DoCSVExport(string toolTypeName, string spName, DateTime startTime, DateTime endTime)
{
string fileName = string.Format("Export_{0}_{1:yyyyMMddHHmm}_to_{2:yyyyMMddHHmm}.csv", toolTypeName, startTime, endTime);
StringBuilder sb = new();

View File

@ -1,21 +1,32 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using OI.Metrology.Archive.Models;
using OI.Metrology.Shared.Repositories;
using OI.Metrology.Shared.ViewModels;
using System;
namespace OI.Metrology.Archive.Controllers;
//[Authorize]
public class PagesController : Controller
{
protected IMetrologyRepo _Repo;
private readonly IMetrologyRepo _Repo;
private readonly bool _IsTestDatabase;
public PagesController(IMetrologyRepo repo) => _Repo = repo;
public PagesController(AppSettings appSettings, IMetrologyRepo repo)
{
_Repo = repo;
_IsTestDatabase = appSettings.ConnectionString.Contains("test", StringComparison.InvariantCultureIgnoreCase);
}
public override void OnActionExecuted(ActionExecutedContext context)
{
base.OnActionExecuted(context);
ViewBag.IsTestDatabase = _IsTestDatabase;
}
[HttpGet]
[Route("/")]
public IActionResult Index() =>
//return View("Home");
View("RunHeaders");
[HttpGet]

View File

@ -0,0 +1,60 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace OI.Metrology.Archive.Models;
public class AppSettings
{
protected string _ApiLoggingContentTypes;
protected string _ApiLoggingPathPrefixes;
protected string _ApiLogPath;
protected string _AttachmentPath;
protected string _BuildNumber;
protected string _Company;
protected string _ConnectionString;
protected string _GitCommitSeven;
protected string _InboundApiAllowedIPList;
protected string _MonARessource;
protected string _OIExportPath;
protected string _URLs;
protected string _WorkingDirectoryName;
public string ApiLoggingContentTypes => _ApiLoggingContentTypes;
public string ApiLoggingPathPrefixes => _ApiLoggingPathPrefixes;
public string ApiLogPath => _ApiLogPath;
public string AttachmentPath => _AttachmentPath;
public string BuildNumber => _BuildNumber;
public string Company => _Company;
public string ConnectionString => _ConnectionString;
public string GitCommitSeven => _GitCommitSeven;
public string InboundApiAllowedIPList => _InboundApiAllowedIPList;
public string MonARessource => _MonARessource;
public string OIExportPath => _OIExportPath;
public string URLs => _URLs;
public string WorkingDirectoryName => _WorkingDirectoryName;
[JsonConstructor]
public AppSettings(string apiLoggingContentTypes, string apiLoggingPathPrefixes, string apiLogPath, string attachmentPath, string buildNumber, string company, string connectionString, string gitCommitSeven, string inboundApiAllowedIPList, string monARessource, string oiExportPath, string urls, string workingDirectoryName)
{
_ApiLoggingContentTypes = apiLoggingContentTypes;
_ApiLoggingPathPrefixes = apiLoggingPathPrefixes;
_ApiLogPath = apiLogPath;
_AttachmentPath = attachmentPath;
_BuildNumber = buildNumber;
_Company = company;
_ConnectionString = connectionString;
_GitCommitSeven = gitCommitSeven;
_InboundApiAllowedIPList = inboundApiAllowedIPList;
_MonARessource = monARessource;
_OIExportPath = oiExportPath;
_URLs = urls;
_WorkingDirectoryName = workingDirectoryName;
}
public override string ToString()
{
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
return result;
}
}

View File

@ -0,0 +1,46 @@
using System.ComponentModel.DataAnnotations;
using System.Text.Json;
namespace OI.Metrology.Archive.Models.Binder;
public class AppSettings
{
[Display(Name = "Api Logging Content Types"), Required] public string ApiLoggingContentTypes { get; set; }
[Display(Name = "Api Logging Path Prefixes"), Required] public string ApiLoggingPathPrefixes { get; set; }
[Display(Name = "Api Log Path"), Required] public string ApiLogPath { get; set; }
[Display(Name = "Attachment Path"), Required] public string AttachmentPath { get; set; }
[Display(Name = "Build Number"), Required] public string BuildNumber { get; set; }
[Display(Name = "Company"), Required] public string Company { get; set; }
[Display(Name = "Connection String"), Required] public string ConnectionString { get; set; }
[Display(Name = "Git Commit Seven"), Required] public string GitCommitSeven { get; set; }
[Display(Name = "Inbound Api Allowed IP List"), Required] public string InboundApiAllowedIPList { get; set; }
[Display(Name = "MonA Ressource"), Required] public string MonARessource { get; set; }
[Display(Name = "OI Export Path"), Required] public string OIExportPath { get; set; }
[Display(Name = "URLs"), Required] public string URLs { get; set; }
[Display(Name = "Working Directory Name"), Required] public string WorkingDirectoryName { get; set; }
public AppSettings()
{
ApiLoggingContentTypes = string.Empty;
ApiLoggingPathPrefixes = string.Empty;
ApiLogPath = string.Empty;
AttachmentPath = string.Empty;
BuildNumber = string.Empty;
Company = string.Empty;
ConnectionString = string.Empty;
GitCommitSeven = string.Empty;
InboundApiAllowedIPList = string.Empty;
MonARessource = string.Empty;
OIExportPath = string.Empty;
URLs = string.Empty;
WorkingDirectoryName = string.Empty;
}
public override string ToString()
{
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
return result;
}
}

View File

@ -0,0 +1,44 @@
using Microsoft.Extensions.Configuration;
using System;
using System.Linq;
using System.Text.Json;
namespace OI.Metrology.Archive.Models.Stateless;
public abstract class AppSettings
{
#nullable enable
public static Models.AppSettings Get(IConfigurationRoot configurationRoot)
{
Models.AppSettings? result;
Binder.AppSettings appSettings = configurationRoot.Get<Binder.AppSettings>();
string json = JsonSerializer.Serialize(appSettings, new JsonSerializerOptions() { WriteIndented = true });
result = JsonSerializer.Deserialize<Models.AppSettings>(json);
if (result is null)
throw new Exception(json);
if (string.IsNullOrEmpty(result.Company))
throw new Exception(json);
string jsonThis = result.ToString();
if (jsonThis != json)
{
int? check = null;
int min = new int[] { json.Length, jsonThis.Length }.Min();
for (int i = 0; i < min; i++)
{
if (json[i] == jsonThis[i])
continue;
check = i;
break;
}
if (check is null)
throw new Exception();
string a = json[..check.Value].Split(',')[^1];
string b = json[check.Value..].Split(',')[0];
throw new Exception($"{a}{b}");
}
return result;
}
}

View File

@ -5,10 +5,13 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Hosting.WindowsServices;
using Microsoft.Extensions.Logging;
using OI.Metrology.Archive.Models;
using OI.Metrology.Archive.Repositories;
using OI.Metrology.Archive.Services;
using OI.Metrology.Shared.Models;
using OI.Metrology.Shared.Repositories;
using OI.Metrology.Shared.Services;
using Serilog;
using System;
using System.IO;
using System.Reflection;
@ -18,52 +21,61 @@ namespace OI.Metrology.Archive;
public class Program
{
private static string GetWebRoot()
private static (string, WebApplicationOptions) Get(string[] args)
{
string result;
string webRootPath;
Assembly assembly = Assembly.GetExecutingAssembly();
string assemblyName = assembly.GetName()?.Name;
if (string.IsNullOrEmpty(assemblyName))
throw new Exception();
string net6 = "net6.0";
string baseAssemblyName = assemblyName.Split('.')[0];
if (WindowsServiceHelpers.IsWindowsService())
result = Path.Combine("D:", net6, baseAssemblyName, "wwwroot");
webRootPath = Path.Combine(AppContext.BaseDirectory, "wwwroot");
else
result = Path.Combine(AppContext.BaseDirectory.Split(baseAssemblyName)[0], baseAssemblyName, "Client", "bin", "Debug", net6, "wwwroot");
if (!Directory.Exists(result))
result = string.Empty;
return result;
webRootPath = Path.Combine(AppContext.BaseDirectory.Split(baseAssemblyName)[0], baseAssemblyName, "wwwroot");
if (!Directory.Exists(webRootPath))
webRootPath = string.Empty;
WebApplicationOptions webApplicationOptions = new()
{
Args = args,
ContentRootPath = AppContext.BaseDirectory,
WebRootPath = webRootPath
};
return new(assemblyName, webApplicationOptions);
}
public static int Main(string[] args)
{
WebApplicationOptions options = new()
{
Args = args,
ContentRootPath = AppContext.BaseDirectory,
WebRootPath = GetWebRoot()
};
WebApplicationBuilder webApplicationBuilder = WebApplication.CreateBuilder(options);
LoggerConfiguration loggerConfiguration = new();
(string assemblyName, WebApplicationOptions webApplicationOptions) = Get(args);
WebApplicationBuilder webApplicationBuilder = WebApplication.CreateBuilder(webApplicationOptions);
_ = webApplicationBuilder.Configuration.AddUserSecrets<Program>();
AppSettings appSettings = Models.Stateless.AppSettings.Get(webApplicationBuilder.Configuration);
if (string.IsNullOrEmpty(appSettings.WorkingDirectoryName))
throw new Exception("Working directory name must have a value!");
string workingDirectory = IWorkingDirectory.GetWorkingDirectory(assemblyName, appSettings.WorkingDirectoryName);
Environment.SetEnvironmentVariable(nameof(workingDirectory), workingDirectory);
_ = ConfigurationLoggerConfigurationExtensions.Configuration(loggerConfiguration.ReadFrom, webApplicationBuilder.Configuration);
_ = SerilogHostBuilderExtensions.UseSerilog(webApplicationBuilder.Host);
Log.Logger = loggerConfiguration.CreateLogger();
Serilog.ILogger log = Log.ForContext<Program>();
try
{
// this prevents validation errors from being handled by ASP.NET and not hitting our custom error handle
_ = webApplicationBuilder.Services.Configure<ApiBehaviorOptions>(options => options.SuppressModelStateInvalidFilter = true);
_ = webApplicationBuilder.Services.AddControllersWithViews();
_ = new MetrologyRepo(new SQLDbConnectionFactory(webApplicationBuilder.Configuration), null);
_ = webApplicationBuilder.Services.AddSingleton<IDbConnectionFactory, SQLDbConnectionFactory>();
_ = webApplicationBuilder.Services.AddScoped<IMetrologyRepo, MetrologyRepo>();
_ = new MetrologyRepo(new SQLDbConnectionFactory(appSettings), null);
_ = webApplicationBuilder.Services.AddDistributedMemoryCache();
_ = webApplicationBuilder.Services.AddMemoryCache();
_ = webApplicationBuilder.Services.AddSingleton<AppSettings, AppSettings>(_ => appSettings);
_ = webApplicationBuilder.Services.AddScoped<IAttachmentsService, AttachmentsService>();
_ = webApplicationBuilder.Services.AddScoped<IInboundDataService, InboundDataService>();
_ = webApplicationBuilder.Services.AddMemoryCache();
_ = webApplicationBuilder.Services.AddDistributedMemoryCache();
_ = webApplicationBuilder.Services.AddScoped<IMetrologyRepo, MetrologyRepo>();
_ = webApplicationBuilder.Services.AddSingleton<IDbConnectionFactory, SQLDbConnectionFactory>();
_ = webApplicationBuilder.Services.AddSwaggerGen();
_ = webApplicationBuilder.Services.AddSession(sessionOptions =>
{
// Set a short timeout for easy testing.
sessionOptions.IdleTimeout = TimeSpan.FromSeconds(2000);
sessionOptions.Cookie.HttpOnly = true;
// Make the session cookie essential
sessionOptions.Cookie.IsEssential = true;
}
);
@ -77,26 +89,41 @@ public class Program
});
}
WebApplication webApplication = webApplicationBuilder.Build();
if (webApplicationBuilder.Environment.IsDevelopment())
if (!webApplicationBuilder.Environment.IsDevelopment())
{
_ = webApplication.UseExceptionHandler("/Error");
_ = webApplication.UseHsts();
}
else
{
if (string.IsNullOrEmpty(appSettings.URLs))
{
Environment.ExitCode = -1;
webApplication.Lifetime.StopApplication();
}
_ = webApplication.UseSwagger();
_ = webApplication.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Archive V1"));
}
_ = webApplication.Lifetime.ApplicationStopped.Register(Log.CloseAndFlush);
_ = ApplicationBuilderSerilogClientExtensions.UseSerilogIngestion(webApplication);
_ = SerilogApplicationBuilderExtensions.UseSerilogRequestLogging(webApplication);
_ = webApplication.UseStaticFiles();
_ = webApplication.UseSession();
_ = webApplication.UseHttpsRedirection();
_ = webApplication.UseMiddleware<ApiLoggingMiddleware>();
_ = webApplication.MapControllers();
log.Information("Starting Web Application");
webApplication.Run();
return 0;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
log.Fatal(ex, "Host terminated unexpectedly");
return 1;
}
finally
{
Log.CloseAndFlush();
}
}

View File

@ -14,17 +14,16 @@ namespace OI.Metrology.Archive.Repositories;
public class MetrologyRepo : IMetrologyRepo
{
private IDbConnectionFactory DBConnectionFactory { get; }
private readonly IDbConnectionFactory _DBConnectionFactory;
private readonly IMemoryCache _Cache;
public MetrologyRepo(IDbConnectionFactory dbConnectionFactory, IMemoryCache memoryCache)
{
DBConnectionFactory = dbConnectionFactory;
_DBConnectionFactory = dbConnectionFactory;
_Cache = memoryCache;
}
private DbConnection GetDbConnection() => DBConnectionFactory.GetDbConnection(Constants.ConnStringName);
private DbConnection GetDbConnection2() => DBConnectionFactory.GetDbConnection(Constants.ConnStringName2);
private DbConnection GetDbConnection() => _DBConnectionFactory.GetDbConnection();
protected DbProviderFactory GetDbProviderFactory(IDbConnection conn) => DbProviderFactories.GetFactory(conn.GetType().Namespace);
@ -57,19 +56,6 @@ public class MetrologyRepo : IMetrologyRepo
string cacheKey = "GetToolTypes";
if (_Cache.TryGetValue(cacheKey, out cached))
return cached;
//List<string> r = new List<string>();
//r.Add("BioRad");
//r.Add("CDE");
//r.Add("Tencor");
//r.Add("MercuryProbe");
//r.Add("StratusBioRad");
//r.Add("TencorSP1");
//CacheItem(cacheKey, r);
//return r;
//var conn =
using DbConnection conn = GetDbConnection();
IEnumerable<ToolType> r = conn.Query<ToolType>("SELECT * FROM ToolType");
@ -95,7 +81,7 @@ public class MetrologyRepo : IMetrologyRepo
return r;
}
//Changed by Jonathan : Changed this as the table ToolType doesn't exist in the Metrology_Archive DB
// Changed by Jonathan : Changed this as the table ToolType doesn't exist in the Metrology_Archive DB
public ToolType GetToolTypeByID(int id)
{
ToolType cached;
@ -103,7 +89,6 @@ public class MetrologyRepo : IMetrologyRepo
if (_Cache.TryGetValue(cacheKey, out cached))
return cached;
//using (var conn = GetDbConnection2())
using DbConnection conn = GetDbConnection();
ToolType r = conn.QueryFirstOrDefault<ToolType>(
"SELECT * FROM ToolType WHERE ID = @id",
@ -113,12 +98,10 @@ public class MetrologyRepo : IMetrologyRepo
return r;
}
//Changed by Jonathan : Changed this to look at Metrology DB because table ToolTypeMetaData does not exist in Metrology_Archive. This still fails when BioRad is the tool.
// Changed by Jonathan : Changed this to look at Metrology DB because table ToolTypeMetaData does not exist in Metrology_Archive. This still fails when BioRad is the tool.
public IEnumerable<ToolTypeMetadata> GetToolTypeMetadataByToolTypeID(int id)
{
string cacheKey = "GetToolTypeMetadataByToolTypeID_" + id.ToString();
//if (_cache.TryGetValue(cacheKey, out cached))
//return cached;
using DbConnection conn = GetDbConnection();
IEnumerable<ToolTypeMetadata> r = conn.Query<ToolTypeMetadata>(
@ -335,8 +318,8 @@ public class MetrologyRepo : IMetrologyRepo
_ = sb.AppendFormat(" FROM [{0}] ", tableName);
return sb.ToString();
}
//Set DB Connection based on isArchive flag, for prod need to set isArchive outside of this function.
public DataTable GetHeaders(int toolTypeId, DateTime? startTime, DateTime? endTime, int? pageNo, int? pageSize, long? headerId, out long totalRecords, bool isArchive)
public DataTable GetHeaders(int toolTypeId, DateTime? startTime, DateTime? endTime, int? pageNo, int? pageSize, long? headerId, out long totalRecords)
{
ToolType tt = GetToolTypeByID(toolTypeId);
if (tt == null)
@ -348,14 +331,7 @@ public class MetrologyRepo : IMetrologyRepo
DataTable dt = new();
//bool isArchive = true;
DbConnection conn = GetDbConnection();
if (isArchive == true)
{
conn = GetDbConnection2();
}
using (conn)
{
System.Text.StringBuilder sb = new();
@ -433,10 +409,9 @@ public class MetrologyRepo : IMetrologyRepo
return dt;
}
//Go Here Next
public DataTable GetData(int toolTypeId, long headerid, bool isArchive)
// Go Here Next
public DataTable GetData(int toolTypeId, long headerid)
{
//isArchive = true;
ToolType tt = GetToolTypeByID(toolTypeId);
if (tt == null)
throw new Exception("Invalid tool type ID");
@ -448,11 +423,6 @@ public class MetrologyRepo : IMetrologyRepo
DataTable dt = new();
DbConnection conn = GetDbConnection();
if (isArchive == true)
{
conn = GetDbConnection2();
}
using (conn)
{
System.Text.StringBuilder sb = new();
@ -467,7 +437,6 @@ public class MetrologyRepo : IMetrologyRepo
DbCommand cmd = factory.CreateCommand();
_ = sb.Append("WHERE [HeaderID] = @HeaderID ");
//sb.Append("WHERE [OriginID] = @HeaderID ");
if (!string.IsNullOrWhiteSpace(tt.DataGridSortBy))
{
@ -537,7 +506,7 @@ public class MetrologyRepo : IMetrologyRepo
return dt;
}
public string GetAttachmentInsertDateByGUID(String tableName, Guid attachmentId)
public string GetAttachmentInsertDateByGUID(string tableName, Guid attachmentId)
{
using DbConnection conn = GetDbConnection();
string sql = "";
@ -554,7 +523,6 @@ public class MetrologyRepo : IMetrologyRepo
}
public DataTable GetDataSharePoint(int toolTypeId, string headerid)
{
//isArchive = true;
ToolType tt = GetToolTypeByID(toolTypeId);
if (tt == null)
throw new Exception("Invalid tool type ID");
@ -566,10 +534,6 @@ public class MetrologyRepo : IMetrologyRepo
DataTable dt = new();
DbConnection conn = GetDbConnection();
//if (isArchive == true)
//{
// conn = GetDbConnection2();
//}
using (conn)
{
@ -585,15 +549,12 @@ public class MetrologyRepo : IMetrologyRepo
DbCommand cmd = factory.CreateCommand();
_ = sb.Append("WHERE [Title] LIKE '%" + headerid + "%' ");
//sb.Append("WHERE [OriginID] = @HeaderID ");
if (!string.IsNullOrWhiteSpace(tt.DataGridSortBy))
{
_ = sb.AppendFormat("ORDER BY {0} ", tt.DataGridSortBy);
}
//AddParameter(cmd, "@HeaderID", headerid);
cmd.Connection = conn;
cmd.CommandText = sb.ToString();
cmd.CommandType = CommandType.Text;
@ -716,18 +677,13 @@ public class MetrologyRepo : IMetrologyRepo
return ds;
}
public IEnumerable<HeaderCommon> GetHeaderTitles(int toolTypeId, int? pageNo, int? pageSize, out long totalRecords, bool isArchive)
public IEnumerable<HeaderCommon> GetHeaderTitles(int toolTypeId, int? pageNo, int? pageSize, out long totalRecords)
{
ToolType tt = GetToolTypeByID(toolTypeId);
if (tt == null)
throw new Exception("Invalid tool type ID");
DbConnection conn = GetDbConnection();
if (isArchive == true)
{
conn = GetDbConnection2();
}
using (conn)
{
string sql = $"SELECT ID, InsertDate, AttachmentID, Title, [Date] FROM {tt.HeaderTableName} ORDER BY [Date] DESC ";
@ -753,7 +709,7 @@ public class MetrologyRepo : IMetrologyRepo
}
}
public IEnumerable<KeyValuePair<string, string>> GetHeaderFields(int toolTypeId, long headerid, bool isArchive)
public IEnumerable<KeyValuePair<string, string>> GetHeaderFields(int toolTypeId, long headerid)
{
ToolType tt = GetToolTypeByID(toolTypeId);
if (tt == null)
@ -766,11 +722,6 @@ public class MetrologyRepo : IMetrologyRepo
List<KeyValuePair<string, string>> r = new();
DbConnection conn = GetDbConnection();
if (isArchive == true)
{
conn = GetDbConnection2();
}
using (conn)
{
DbProviderFactory factory = GetDbProviderFactory(conn);
@ -811,7 +762,7 @@ public class MetrologyRepo : IMetrologyRepo
using DbConnection conn = GetDbConnection();
return conn.Query<AwaitingDispo>("GetAwaitingDispo", commandType: CommandType.StoredProcedure);
}
//Jonathan changed this to remove the reviewDate update on the database.
// Jonathan changed this to remove the reviewDate update on the database.
public int UpdateReviewDate(int toolTypeId, long headerId, bool clearDate)
{
ToolType tt = GetToolTypeByID(toolTypeId);
@ -821,7 +772,7 @@ public class MetrologyRepo : IMetrologyRepo
using DbConnection conn = GetDbConnection();
if (clearDate)
{
//if it's already past the 6 hour window, then it won't show in queue anyway, so need to return value so we can show that
// if it's already past the 6 hour window, then it won't show in queue anyway, so need to return value so we can show that
string sql = $"SELECT DATEDIFF(HH, INSERTDATE, GETDATE()) FROM [{tt.HeaderTableName}] WHERE ID = @HeaderID";
int hrs = conn.ExecuteScalar<int>(sql, param: new { HeaderId = headerId });
_ = conn.Execute($"UPDATE [{tt.HeaderTableName}] SET ReviewDate = NULL WHERE ID = @HeaderID", new { HeaderID = headerId });
@ -829,7 +780,6 @@ public class MetrologyRepo : IMetrologyRepo
}
else
{
//conn.Execute($"UPDATE [{tt.HeaderTableName}] SET ReviewDate = GETDATE() WHERE ID = @HeaderID", new { HeaderID = headerId });
return 1;
}
}
@ -857,4 +807,9 @@ public class MetrologyRepo : IMetrologyRepo
$"SELECT TOP 1 AttachmentID FROM [{tt.DataTableName}] WHERE Title = @Title ORDER BY InsertDate DESC";
return conn.ExecuteScalar<Guid>(sql, param: new { Title = title });
}
string IMetrologyRepo.GetHeaderInsertDate(int toolTypeId, long headerId) => throw new NotImplementedException();
void IMetrologyRepo.SetHeaderDirName(string tableName, long headerId, string dateDir) => throw new NotImplementedException();
string IMetrologyRepo.GetDataInsertDate(int toolTypeId, long headerId, string title) => throw new NotImplementedException();
void IMetrologyRepo.SetDataDirName(string tableName, long headerId, string title, string dateDir) => throw new NotImplementedException();
}

View File

@ -1,4 +1,4 @@
using Microsoft.Extensions.Configuration;
using OI.Metrology.Archive.Models;
using OI.Metrology.Shared.Repositories;
using System;
using System.Data.Common;
@ -8,22 +8,21 @@ namespace OI.Metrology.Archive.Repositories;
public class SQLDbConnectionFactory : IDbConnectionFactory
{
private IConfiguration Config { get; }
private readonly AppSettings _AppSettings;
public SQLDbConnectionFactory(IConfiguration config) => Config = config;
public SQLDbConnectionFactory(AppSettings appSettings) => _AppSettings = appSettings;
public DbConnection GetDbConnection(String connStringName)
public DbConnection GetDbConnection()
{
DbProviderFactories.RegisterFactory(
typeof(SqlConnection).Namespace,
SqlClientFactory.Instance);
string connStr = Config?.GetConnectionString(connStringName);
if (connStr is null)
throw new Exception("Connection string is missing: " + connStringName);
if (string.IsNullOrEmpty(_AppSettings.ConnectionString))
throw new Exception("Connection string is missing");
DbConnection c = SqlClientFactory.Instance.CreateConnection();
c.ConnectionString = connStr;
c.ConnectionString = _AppSettings.ConnectionString;
c.Open();
return c;
}

View File

@ -1,10 +1,10 @@
using Microsoft.Extensions.Configuration;
using System;
using System;
using System.Globalization;
using System.IO;
namespace OI.Metrology.Archive.Services;
using OI.Metrology.Archive.Models;
using OI.Metrology.Shared.DataModels;
using OI.Metrology.Shared.Repositories;
using OI.Metrology.Shared.Services;
@ -12,19 +12,17 @@ using System.Data.SqlClient;
public class AttachmentsService : IAttachmentsService
{
private IConfiguration Config { get; }
protected IMetrologyRepo _Repo;
private readonly IMetrologyRepo _Repo;
private readonly AppSettings _AppSettings;
public AttachmentsService(IConfiguration config, IMetrologyRepo repo)
public AttachmentsService(AppSettings appSettings, IMetrologyRepo repo)
{
Config = config;
_Repo = repo;
_AppSettings = appSettings;
}
protected Stream GetAttachmentStream(String tableName, Guid attachmentId, string filename)
protected Stream GetAttachmentStream(string tableName, Guid attachmentId, string filename)
{
string attachmentsRootPath = Config[Constants.AttachmentPathKey];
if (attachmentId.Equals(Guid.Empty))
throw new Exception("No attachments found");
@ -36,12 +34,12 @@ public class AttachmentsService : IAttachmentsService
string workWeek = "WW" + weekNum.ToString("00");
string dateDir = year + @"\" + workWeek;
string fullPath = Path.Combine(attachmentsRootPath, tableName + "_", dateDir, attachmentId.ToString(), filename);
string fullPath = Path.Combine(_AppSettings.AttachmentPath, tableName + "_", dateDir, attachmentId.ToString(), filename);
//Check to see if file exists in the "New" directory structure, if not change the path back to the old. and check there
// Check to see if file exists in the "New" directory structure, if not change the path back to the old. and check there
if (!File.Exists(fullPath))
{
fullPath = Path.Combine(attachmentsRootPath, tableName, attachmentId.ToString(), filename);
fullPath = Path.Combine(_AppSettings.AttachmentPath, tableName, attachmentId.ToString(), filename);
}
if (!File.Exists(fullPath))
@ -49,40 +47,20 @@ public class AttachmentsService : IAttachmentsService
return new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
}
//protected System.IO.Stream GetAttachmentStream(String tableName, Guid attachmentId, string filename)
//{
// //This part seems to be key
// var attachmentsRootPath = _config[Constants.AttachmentPathKey];
// //if (attachmentId.Equals(Guid.Empty))
// //throw new Exception("No attachments found");
// //string list = Directory.GetDirectories(attachmentsRootPath).Where(s => s.Contains(attachmentId.ToString())).SingleOrDefault();
// //var fullPath = list;
// var fullPath = System.IO.Path.Combine(attachmentsRootPath, tableName, attachmentId.ToString(), filename);
// if (!System.IO.File.Exists(fullPath))
// throw new Exception("File not found " + fullPath);
// return new System.IO.FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
//}
protected Stream GetAttachmentStreamArchive(String tableName, Guid attachmentId, string filename)
protected Stream GetAttachmentStreamArchive(string tableName, Guid attachmentId, string filename)
{
//This part seems to be key
string attachmentsRootPath = Config[Constants.AttachmentPathKey];
if (attachmentId.Equals(Guid.Empty))
throw new Exception("No attachments found");
string fullPath = Path.Combine(attachmentsRootPath, tableName, "2019\\09", attachmentId.ToString(), filename);
string fullPath = Path.Combine(_AppSettings.AttachmentPath, tableName, "2019\\09", attachmentId.ToString(), filename);
if (!File.Exists(fullPath))
throw new Exception("File not found");
return new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
}
public Stream GetAttachmentStreamByTitle(ToolType toolType, bool header, string title, string filename)
{
if (toolType == null)
@ -98,7 +76,6 @@ public class AttachmentsService : IAttachmentsService
using (SqlConnection connection = new(connectionString))
{
SqlCommand command = new(queryString, connection);
//command.Parameters.AddWithValue("@attachmentId", attachmentId);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
try
@ -112,7 +89,6 @@ public class AttachmentsService : IAttachmentsService
}
finally
{
// Always call Close when done reading.
reader.Close();
}
}
@ -121,14 +97,8 @@ public class AttachmentsService : IAttachmentsService
{
_ = "0" + SearchMonth;
}
_ = SearchDate.Year.ToString();
_ = Config[Constants.AttachmentPathKey];
string tableName;
//var attachmentsRootPath = "\\\\messv02ecc1.ec.local\\EC_Metrology_Si\\MetrologyAttachments\\TencorRunData\\2019\\09";
Guid attachmentId;
if (header)
{
@ -140,7 +110,6 @@ public class AttachmentsService : IAttachmentsService
tableName = toolType.DataTableName;
attachmentId = _Repo.GetDataAttachmentIDByTitle(toolType.ID, title);
}
return GetAttachmentStream(tableName, attachmentId, filename);
}
@ -148,66 +117,18 @@ public class AttachmentsService : IAttachmentsService
{
if (toolType == null)
throw new Exception("Invalid tool type");
/*string queryString = "SELECT * FROM " + toolType.DataTableName + " WHERE AttachmentId = @attachmentId";
if (header)
{
queryString = "SELECT * FROM " + toolType.HeaderTableName + " WHERE AttachmentId = '" + attachmentId + "'";
}
DateTime SearchDate = new DateTime();
string connectionString = @"Server=messv01ec.ec.local\PROD1,53959;Database=Metrology_Archive;Integrated Security=True";
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(queryString, connection);
command.Parameters.AddWithValue("@attachmentId", attachmentId);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
try
{
while (reader.Read())
{
Console.WriteLine(string.Format("{0}", reader["InsertDate"]));// etc
//string test = string.Format("{0}", reader["InsertDate"]);
SearchDate = Convert.ToDateTime(string.Format("{0}", reader["Date"]));
}
}
finally
{
// Always call Close when done reading.
reader.Close();
}
}
string SearchMonth = SearchDate.Month.ToString();
if (SearchDate.Month < 10)
{
SearchMonth = "0" + SearchMonth;
}
string SearchYear = SearchDate.Year.ToString();*/
//string DateSearchTermin = +""+
_ = Config[Constants.AttachmentPathKey];
string tableName;
if (header)
tableName = toolType.HeaderTableName;
else
tableName = toolType.DataTableName;
//System.IO.Stream test = GetAttachmentStream(tableName, attachmentId, filename, SearchYear);
return GetAttachmentStream(tableName, attachmentId, filename);
//return test;
}
public Stream GetAttachmentStreamByAttachmentIdArchive(ToolType toolType, bool header, Guid attachmentId, string filename)
{
if (toolType == null)
throw new Exception("Invalid tool type");
_ = Config[Constants.AttachmentPathKey];
string tableName;
if (header)
tableName = toolType.HeaderTableName;
else
@ -216,7 +137,7 @@ string SearchYear = SearchDate.Year.ToString();*/
return GetAttachmentStreamArchive(tableName, attachmentId, filename);
}
public void SaveAttachment(ToolType toolType, long headerId, string dataUniqueId, string filename, Microsoft.AspNetCore.Http.IFormFile uploadedFile)
private void SaveAttachment(ToolType toolType, long headerId, string dataUniqueId, string filename, Microsoft.AspNetCore.Http.IFormFile uploadedFile)
{
if (toolType == null)
throw new Exception("Invalid tool type");
@ -235,24 +156,16 @@ string SearchYear = SearchDate.Year.ToString();*/
attachmentId = _Repo.GetDataAttachmentID(toolType.ID, headerId, dataUniqueId);
tableName = toolType.DataTableName;
}
if (Equals(attachmentId, Guid.Empty))
throw new Exception("Invalid attachment ID");
string attachmentsRootPath = Config[Constants.AttachmentPathKey];
string directoryPath = Path.Combine(attachmentsRootPath, tableName, attachmentId.ToString());
string directoryPath = Path.Combine(_AppSettings.AttachmentPath, tableName, attachmentId.ToString());
if (!Directory.Exists(directoryPath))
_ = Directory.CreateDirectory(directoryPath);
string fullPath = Path.Combine(directoryPath, filename);
using (FileStream s = new(fullPath, FileMode.Create, FileAccess.ReadWrite, FileShare.None))
{
uploadedFile.CopyTo(s);
}
trans.Complete();
}

View File

@ -10,7 +10,7 @@ namespace OI.Metrology.Archive.Services;
public class InboundDataService : IInboundDataService
{
protected IMetrologyRepo _Repo;
private readonly IMetrologyRepo _Repo;
public InboundDataService(IMetrologyRepo repo) => _Repo = repo;

View File

@ -18,22 +18,28 @@
<form asp-controller="Export" asp-action="ExportData" method="post" class="form-inline">
<div class="form-group">
<label for="ToolType">Tool Type</label>
<div class="form-control" id="ToolType"></div>
<div class="form-control" id="ToolType" name="ToolType"></div>
@Html.ValidationMessage("ToolType", new { @class = "text-danger" })
</div>
<div class="form-group">
<label for="StartDate">Start Time</label>
<div class="form-control mb-2 mr-sm-2" id="StartDateControl"></div>
<div class="form-control mb-2 mr-sm-2" id="StartTimeControl"></div>
@Html.ValidationMessage("StartDate", new { @class = "text-danger" })
</div>
<div class="form-group">
<label for="EndDate">End Time</label>
<div class="form-control mb-2 mr-sm-2" id="EndDateControl"></div>
<div class="form-control mb-2 mr-sm-2" id="EndTimeControl"></div>
</div>&nbsp;&nbsp;
@Html.ValidationMessage("EndDate", new { @class = "text-danger" })
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Export Data</button>
</div>
<div class="form-group">
@Html.ValidationMessage("Exception", new { @class = "text-danger" })
</div>
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
</form>
@ -48,11 +54,7 @@
textKey: "ToolTypeName",
valueKey: "ID",
mode: "dropdown",
width: 150,
itemsRendered: function (evt, ui) {
LoadHeaderGrid();
},
selectionChanged: LoadHeaderGrid
width: 150
});
var startTime = new Date("@Model.StartTime.ToString("yyyy-MM-ddTHH:mm")");

View File

@ -1,5 +1,4 @@

@{
@{
ViewData["Title"] = "Awaiting Disposition";
}
@ -45,8 +44,8 @@
tabIndex: 1,
features: [
{ name: "Selection", mode: "row", multipleSelection: false },
{ name: "Filtering", type: "local"},
{ name: "Sorting", type:"local"},
{ name: "Filtering", type: "local" },
{ name: "Sorting", type: "local" },
]
});

View File

@ -1,10 +1,10 @@

@{
@{
ViewData["Title"] = "Run Headers";
}
<style>
html, body {
html,
body {
height: 100%;
}
@ -12,7 +12,8 @@
height: 90%;
}
#HeaderGrid, #FieldsGrid {
#HeaderGrid,
#FieldsGrid {
font-size: 12px;
}
@ -70,7 +71,7 @@
{ name: "Filtering", type: "local" }
],
columns: [
{ key: "ID", dataType: "number", hidden: true},
{ key: "ID", dataType: "number", hidden: true },
{ key: "Title", dataType: "string", width: "80%" },
{ key: "InsertDate", dataType: "date", format: "dateTime", width: "20%" }
],

View File

@ -3,8 +3,8 @@
ViewData["Title"] = "Run Information";
}
<style>
#HeaderGridDiv, #
Div {
#HeaderGridDiv,
# Div {
font-size: 12px;
}
</style>
@ -29,19 +29,6 @@
<div class="form-group">
<input class="btn btn-primary" type="button" value="Load Headers" id="LoadHeadersButton" />
</div>&nbsp;&nbsp;
@*<div class="form-group">
<label class="form-check-label" for="chkAutoRefresh">
Auto-Refresh
</label>
<input class="form-check-input" type="checkbox" id="chkAutoRefresh">
</div>*@
@*This checkbox below is for archive flag.*@
@*<div class="form-group">
<label class="form-check-label" for="isArchive">
Archive
</label>
<input class="form-check-input" type="checkbox" id="isArchive">
</div>*@
</form>
<div style="height: 300px;" id="HeaderGridDiv">
@ -202,18 +189,11 @@
return;
$("#DataAttachmentFrame").prop("src", attachmentUrlBase + "/data/files/" + attachmentId + "/" + toolType.DisplayDataAttachment);
//if (CheckArchive()) {
// $("#DataAttachmentFrame").prop("src", attachmentUrlBase + "/data/files/" + attachmentId + "/" + toolType.DisplayDataAttachment);
//}
}
}
function LoadHeaderAttachment() {
var toolTypeID = $("#ToolTypeID").text();
var attachmentUrlBase = '@Url.Content("~/api/tooltypes/")' + toolTypeID;
var attachmentId = $("#HeaderAttachmentId").text();
var dateToUse = new Date($("#HeaderDate").text());
@ -222,37 +202,18 @@
if ((attachmentId == null) || (attachmentId === '') || (toolType.DisplayHeaderAttachment == null) || (toolType.DisplayHeaderAttachment === '')) {
$("#HeaderAttachmentFrame").prop("src", "");
} else {
$("#HeaderAttachmentFrame").prop("src", attachmentUrlBase + "/header/files/" + attachmentId + "/" + toolType.DisplayHeaderAttachment + "?isArchive=true&date="+dateToUse);
$("#HeaderAttachmentFrame").prop("src", attachmentUrlBase + "/header/files/" + attachmentId + "/" + toolType.DisplayHeaderAttachment + "?date=" + dateToUse);
}
$("#DataAttachmentFrame").prop("src", "");
}
@*function MarkAsReviewed() {
var toolTypeId = $("#ToolTypeID").text();
var headerId = $("#HeaderId").text();
$.ajax({
type: "POST",
url: "@Url.Content("~/api/awaitingdispo/markasreviewed")?tooltypeid=" + toolTypeId + "&headerid=" + headerId,
success: function () {
},
error: function (e, ajaxOptions, ex) {
DisplayWSMessage("error", "There was an error marking header as reviewed.", e, ex);
$("#ReviewButton").prop("disabled", false);
}
});
}*@
function CheckDate() {
var date = new Date($("#HeaderDate").text());
return date;
}
function LoadDetails() {
ShowDetailsDiv();
LoadHeaderAttachment();
var dateToUse = $("#HeaderDate").text();
var gridCreated = $("#DetailsGrid").data("igGrid");
@ -269,19 +230,12 @@
else {
var detailsURL = "@Url.Content("~/api/tooltypes/")" + toolTypeID + "/headers/" + headerId + "/data";
}
//Changed from here
//if (CheckArchive() == true) {
// detailsURL = detailsURL + "?isArchive=true";
//}
//Changed to here
var gridColumns = [
{ key: "AttachmentID", dataType: "string", hidden: true },
{ key: "Title", dataType: "string", hidden: true },
];
for (var i = 0; i < toolTypeMetaData.length; i++)
{
for (var i = 0; i < toolTypeMetaData.length; i++) {
var f = toolTypeMetaData[i];
if ((f.Header == false) && (f.GridDisplayOrder > 0)) {
var col = {
@ -312,9 +266,7 @@
],
columns: gridColumns,
dataSource: detailsURL,
responseDataKey: "Results",
//dataBound: MarkAsReviewed,
responseDataKey: "Results"
};
if ((toolType != null) && (toolType.DataGridAttributes != null)) {
@ -329,8 +281,7 @@
function RequestHeaderData()
{
function RequestHeaderData() {
var startDate = $("#StartDate").igDatePicker("value");
var startTime = $("#StartTime").igTimePicker("value");
@ -350,7 +301,6 @@
if (initialHeaderId > 0) {
headerId = initialHeaderId;
parms.headerid = headerId;
//isArchive = CheckArchive()
$("#HeaderId").text(headerId);
$("#HeaderAttachmentId").text(initialHeaderAttachmentId);
initialHeaderId = -1;
@ -358,18 +308,13 @@
var headerURL = "@Url.Content("~/api/tooltypes/")" + toolType.ID + "/headers?" + $.param(parms);
//if (CheckArchive() == true) {
// headerURL = headerURL + "&isArchive=true";
//}
var gridColumns = [
{ key: "ID", dataType: "number", hidden: true },
{ key: "AttachmentID", dataType: "string", hidden: true },
{ key: "Title", dataType: "string", hidden: true },
];
for (var i = 0; i < toolTypeMetaData.length; i++)
{
for (var i = 0; i < toolTypeMetaData.length; i++) {
var f = toolTypeMetaData[i];
if ((f.Header == true) && (f.GridDisplayOrder > 0)) {
var col = {
@ -395,11 +340,11 @@
height: "100%",
width: "100%",
features: [
{ name: "Paging", type: "local", recordCountKey: "TotalRows", pageSize: 100, pageSizeList : [50, 100, 250, 500], pageSizeUrlKey: "pageSize", "pageIndexUrlKey": "page" },
{ name: "Paging", type: "local", recordCountKey: "TotalRows", pageSize: 100, pageSizeList: [50, 100, 250, 500], pageSizeUrlKey: "pageSize", "pageIndexUrlKey": "page" },
{ name: "Selection", mode: "row", rowSelectionChanged: HeaderSelectionChanged },
{ name: "Filtering", type: "local" },
{ name: 'Resizing' },
{ name: "Sorting", type:"local"}
{ name: "Sorting", type: "local" }
],
columns: gridColumns,
dataSource: headerURL,
@ -427,7 +372,7 @@
type: "POST",
url: "@Url.Content("~/api/awaitingdispo/markasawaiting")?tooltypeid=" + toolTypeId + "&headerid=" + headerId,
success: function (e) {
DisplayWSMessage("info", "Marked as awaiting disposition",e);
DisplayWSMessage("info", "Marked as awaiting disposition", e);
$("#ReviewButton").prop("disabled", false);
},
error: function (e, ajaxOptions, ex) {
@ -487,13 +432,7 @@
width: 110
});
}
//function CheckArchive() {
// var isArchive = new Boolean(false);
// isArchive = document.getElementById("isArchive").checked;
// return isArchive;
//}
$(document).ready(function () {
$("#ToolType").igCombo({
@ -507,7 +446,7 @@
LoadHeaderGrid();
},
selectionChanged: LoadHeaderGrid,
initialSelectedItems: [ { value: @Model.ToolTypeID } ]
initialSelectedItems: [{ value: @Model.ToolTypeID }]
});
SetInitialDateTimes();
@ -522,13 +461,6 @@
$("#OIExportButton").click(OIExportButton);
//setInterval(function () {
// if ($("#chkAutoRefresh").is(':checked')) {
// SetInitialDateTimes();
// $("#LoadHeadersButton").click();
// }
// }, 180000);
});
</script>

View File

@ -1,5 +1,6 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
@ -8,7 +9,8 @@
<script src="~/js/modernizr-3.6.0-custom.js" type="text/javascript" asp-append-version="true"></script>
<link href="~/styles/bootstrap.min.css" rel="stylesheet" asp-append-version="true" />
<link href="~/igniteui/css/themes/bootstrap3/default/infragistics.theme.css" rel="stylesheet" asp-append-version="true" />
<link href="~/igniteui/css/themes/bootstrap3/default/infragistics.theme.css" rel="stylesheet"
asp-append-version="true" />
<link href="~/igniteui/css/structure/infragistics.css" rel="stylesheet" asp-append-version="true" />
<link href="~/styles/site.css" rel="stylesheet" asp-append-version="true" />
@ -32,6 +34,7 @@
});
</script>
</head>
<body>
@{
bool isTestDatabase = false;
@ -40,7 +43,6 @@
{
Boolean.TryParse(Convert.ToString(testDatabaseValue), out isTestDatabase);
}
}
<div class="navbar navbar-fixed-top @(isTestDatabase ? "test-database" : "" )">
<div class="container-fluid">
@ -88,5 +90,5 @@
<script src="~/js/respond.min.js" type="text/javascript" asp-append-version="true"></script>
@RenderSection("scripts", required: false)
</body>
</html>
</html>

View File

@ -6,11 +6,7 @@
"AttachmentPath": "\\\\messv02ecc1.ec.local\\EC_Metrology_Si\\MetrologyAttachments",
"BuildNumber": "1",
"Company": "Infineon Technologies Americas Corp.",
"ConnectionStrings": {
"SQL": "Data Source=messv01ec.ec.local\\PROD1,53959;Integrated Security=True;Initial Catalog=Metrology_Archive;",
"SQL2": "Data Source=messv01ec.ec.local\\PROD1,53959;Integrated Security=True;Initial Catalog=Metrology_Archive;",
"SQL3": "\"Server=.\\\\messv01ec.ec.local\\PROD1,53959;Database=Metrology_Archive;User Id=sa;Password=2BeChanged!;\";"
},
"ConnectionString": "Data Source=messv01ec.ec.local\\PROD1,53959;Integrated Security=True;Initial Catalog=Metrology_Archive;",
"GitCommitSeven": "1234567",
"Logging": {
"LogLevel": {
@ -21,7 +17,7 @@
}
},
"InboundApiAllowedIPList": "",
"OIExportPath": "\\\\openinsight-db-srv.na.infineon.com\\apps\\Metrology\\NewSiteData",
"OIExportPath": "\\\\openinsight-db-srv.na.infineon.com\\apps\\Metrology\\Data",
"Serilog": {
"Using": [
"Serilog.Sinks.Console",

View File

@ -6,11 +6,7 @@
"AttachmentPath": "\\\\messv02ecc1.ec.local\\EC_Metrology_Si\\MetrologyAttachments",
"BuildNumber": "1",
"Company": "Infineon Technologies Americas Corp.",
"ConnectionStrings": {
"SQL": "Data Source=messv01ec.ec.local\\PROD1,53959;Integrated Security=True;Initial Catalog=Metrology_Archive;",
"SQL2": "Data Source=messv01ec.ec.local\\PROD1,53959;Integrated Security=True;Initial Catalog=Metrology_Archive;",
"SQL3": "\"Server=.\\\\messv01ec.ec.local\\PROD1,53959;Database=Metrology_Archive;User Id=sa;Password=2BeChanged!;\";"
},
"ConnectionString": "Data Source=messv01ec.ec.local\\PROD1,53959;Integrated Security=True;Initial Catalog=Metrology_Archive;",
"GitCommitSeven": "1234567",
"Logging": {
"LogLevel": {
@ -21,7 +17,7 @@
}
},
"InboundApiAllowedIPList": "",
"OIExportPath": "\\\\openinsight-db-srv.na.infineon.com\\apps\\Metrology\\NewSiteData",
"OIExportPath": "\\\\openinsight-db-srv.na.infineon.com\\apps\\Metrology\\Data",
"Serilog": {
"Using": [
"Serilog.Sinks.Console",
@ -59,6 +55,6 @@
"Application": "Sample"
}
},
"URLs": "https://localhost:7130;http://localhost:5126",
"URLs": "http://localhost:5002;",
"WorkingDirectoryName": "IFXApps"
}

View File

@ -1,66 +0,0 @@
{
"version": "1.0",
"defaultProvider": "filesystem",
"libraries": [
{
"provider": "filesystem",
"library": "D:/cdnjs/bootstrap@5.1.3/css",
"destination": "wwwroot/lib/bootstrap/css"
},
{
"provider": "filesystem",
"library": "D:/cdnjs/bootstrap@5.1.3/js",
"destination": "wwwroot/lib/bootstrap/js"
},
{
"provider": "filesystem",
"library": "D:/cdnjs/bootstrap@5.1.3/scss",
"destination": "wwwroot/lib/bootstrap/scss"
},
{
"provider": "filesystem",
"library": "D:/cdnjs/bootstrap@5.1.3/scss/forms",
"destination": "wwwroot/lib/bootstrap/scss/forms"
},
{
"provider": "filesystem",
"library": "D:/cdnjs/bootstrap@5.1.3/scss/helpers",
"destination": "wwwroot/lib/bootstrap/scss/helpers"
},
{
"provider": "filesystem",
"library": "D:/cdnjs/bootstrap@5.1.3/scss/mixins",
"destination": "wwwroot/lib/bootstrap/scss/mixins"
},
{
"provider": "filesystem",
"library": "D:/cdnjs/bootstrap@5.1.3/scss/utilities",
"destination": "wwwroot/lib/bootstrap/scss/utilities"
},
{
"provider": "filesystem",
"library": "D:/cdnjs/bootstrap@5.1.3/scss/vendor",
"destination": "wwwroot/lib/bootstrap/scss/vendor"
},
{
"provider": "filesystem",
"library": "D:/cdnjs/jquery@3.6.0/",
"destination": "wwwroot/lib/jquery/"
},
{
"provider": "filesystem",
"library": "D:/cdnjs/jqueryui@1.12.1/",
"destination": "wwwroot/lib/jquery-ui/"
},
{
"provider": "filesystem",
"library": "D:/cdnjs/jqueryui@1.12.1/images",
"destination": "wwwroot/lib/jquery-ui/images"
},
{
"provider": "filesystem",
"library": "D:/cdnjs/jqueryui@1.12.1/themes",
"destination": "wwwroot/lib/jquery-ui/themes"
}
]
}

View File

@ -1,18 +0,0 @@
{
"version": "1.0",
"defaultProvider": "cdnjs",
"libraries": [
{
"library": "jquery@3.6.0",
"destination": "wwwroot/lib/jquery/"
},
{
"library": "jqueryui@1.12.1",
"destination": "wwwroot/lib/jquery-ui/"
},
{
"library": "bootstrap@5.1.3",
"destination": "wwwroot/lib/bootstrap/"
}
]
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,485 +0,0 @@
/*!
* Bootstrap Reboot v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
:root {
--bs-blue: #0d6efd;
--bs-indigo: #6610f2;
--bs-purple: #6f42c1;
--bs-pink: #d63384;
--bs-red: #dc3545;
--bs-orange: #fd7e14;
--bs-yellow: #ffc107;
--bs-green: #198754;
--bs-teal: #20c997;
--bs-cyan: #0dcaf0;
--bs-white: #fff;
--bs-gray: #6c757d;
--bs-gray-dark: #343a40;
--bs-gray-100: #f8f9fa;
--bs-gray-200: #e9ecef;
--bs-gray-300: #dee2e6;
--bs-gray-400: #ced4da;
--bs-gray-500: #adb5bd;
--bs-gray-600: #6c757d;
--bs-gray-700: #495057;
--bs-gray-800: #343a40;
--bs-gray-900: #212529;
--bs-primary: #0d6efd;
--bs-secondary: #6c757d;
--bs-success: #198754;
--bs-info: #0dcaf0;
--bs-warning: #ffc107;
--bs-danger: #dc3545;
--bs-light: #f8f9fa;
--bs-dark: #212529;
--bs-primary-rgb: 13, 110, 253;
--bs-secondary-rgb: 108, 117, 125;
--bs-success-rgb: 25, 135, 84;
--bs-info-rgb: 13, 202, 240;
--bs-warning-rgb: 255, 193, 7;
--bs-danger-rgb: 220, 53, 69;
--bs-light-rgb: 248, 249, 250;
--bs-dark-rgb: 33, 37, 41;
--bs-white-rgb: 255, 255, 255;
--bs-black-rgb: 0, 0, 0;
--bs-body-color-rgb: 33, 37, 41;
--bs-body-bg-rgb: 255, 255, 255;
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
--bs-body-font-family: var(--bs-font-sans-serif);
--bs-body-font-size: 1rem;
--bs-body-font-weight: 400;
--bs-body-line-height: 1.5;
--bs-body-color: #212529;
--bs-body-bg: #fff;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
@media (prefers-reduced-motion: no-preference) {
:root {
scroll-behavior: smooth;
}
}
body {
margin: 0;
font-family: var(--bs-body-font-family);
font-size: var(--bs-body-font-size);
font-weight: var(--bs-body-font-weight);
line-height: var(--bs-body-line-height);
color: var(--bs-body-color);
text-align: var(--bs-body-text-align);
background-color: var(--bs-body-bg);
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
hr {
margin: 1rem 0;
color: inherit;
background-color: currentColor;
border: 0;
opacity: 0.25;
}
hr:not([size]) {
height: 1px;
}
h6, h5, h4, h3, h2, h1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-bs-original-title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul {
padding-left: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: 0.5rem;
margin-left: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 0.875em;
}
mark {
padding: 0.2em;
background-color: #fcf8e3;
}
sub,
sup {
position: relative;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
a {
color: #0d6efd;
text-decoration: underline;
}
a:hover {
color: #0a58ca;
}
a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: inherit;
text-decoration: none;
}
pre,
code,
kbd,
samp {
font-family: var(--bs-font-monospace);
font-size: 1em;
direction: ltr /* rtl:ignore */;
unicode-bidi: bidi-override;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
font-size: 0.875em;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: #d63384;
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.2rem 0.4rem;
font-size: 0.875em;
color: #fff;
background-color: #212529;
border-radius: 0.2rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
font-weight: 700;
}
figure {
margin: 0 0 1rem;
}
img,
svg {
vertical-align: middle;
}
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: #6c757d;
text-align: left;
}
th {
text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
label {
display: inline-block;
}
button {
border-radius: 0;
}
button:focus:not(:focus-visible) {
outline: 0;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
select {
text-transform: none;
}
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
select:disabled {
opacity: 1;
}
[list]::-webkit-calendar-picker-indicator {
display: none;
}
button,
[type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
button:not(:disabled),
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
::-moz-focus-inner {
padding: 0;
border-style: none;
}
textarea {
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
float: left;
width: 100%;
padding: 0;
margin-bottom: 0.5rem;
font-size: calc(1.275rem + 0.3vw);
line-height: inherit;
}
@media (min-width: 1200px) {
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: left;
}
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
[type=search] {
outline-offset: -2px;
-webkit-appearance: textfield;
}
/* rtl:raw:
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
*/
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-color-swatch-wrapper {
padding: 0;
}
::-webkit-file-upload-button {
font: inherit;
}
::file-selector-button {
font: inherit;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
iframe {
border: 0;
}
summary {
display: list-item;
cursor: pointer;
}
progress {
vertical-align: baseline;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,482 +0,0 @@
/*!
* Bootstrap Reboot v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
:root {
--bs-blue: #0d6efd;
--bs-indigo: #6610f2;
--bs-purple: #6f42c1;
--bs-pink: #d63384;
--bs-red: #dc3545;
--bs-orange: #fd7e14;
--bs-yellow: #ffc107;
--bs-green: #198754;
--bs-teal: #20c997;
--bs-cyan: #0dcaf0;
--bs-white: #fff;
--bs-gray: #6c757d;
--bs-gray-dark: #343a40;
--bs-gray-100: #f8f9fa;
--bs-gray-200: #e9ecef;
--bs-gray-300: #dee2e6;
--bs-gray-400: #ced4da;
--bs-gray-500: #adb5bd;
--bs-gray-600: #6c757d;
--bs-gray-700: #495057;
--bs-gray-800: #343a40;
--bs-gray-900: #212529;
--bs-primary: #0d6efd;
--bs-secondary: #6c757d;
--bs-success: #198754;
--bs-info: #0dcaf0;
--bs-warning: #ffc107;
--bs-danger: #dc3545;
--bs-light: #f8f9fa;
--bs-dark: #212529;
--bs-primary-rgb: 13, 110, 253;
--bs-secondary-rgb: 108, 117, 125;
--bs-success-rgb: 25, 135, 84;
--bs-info-rgb: 13, 202, 240;
--bs-warning-rgb: 255, 193, 7;
--bs-danger-rgb: 220, 53, 69;
--bs-light-rgb: 248, 249, 250;
--bs-dark-rgb: 33, 37, 41;
--bs-white-rgb: 255, 255, 255;
--bs-black-rgb: 0, 0, 0;
--bs-body-color-rgb: 33, 37, 41;
--bs-body-bg-rgb: 255, 255, 255;
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
--bs-body-font-family: var(--bs-font-sans-serif);
--bs-body-font-size: 1rem;
--bs-body-font-weight: 400;
--bs-body-line-height: 1.5;
--bs-body-color: #212529;
--bs-body-bg: #fff;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
@media (prefers-reduced-motion: no-preference) {
:root {
scroll-behavior: smooth;
}
}
body {
margin: 0;
font-family: var(--bs-body-font-family);
font-size: var(--bs-body-font-size);
font-weight: var(--bs-body-font-weight);
line-height: var(--bs-body-line-height);
color: var(--bs-body-color);
text-align: var(--bs-body-text-align);
background-color: var(--bs-body-bg);
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
hr {
margin: 1rem 0;
color: inherit;
background-color: currentColor;
border: 0;
opacity: 0.25;
}
hr:not([size]) {
height: 1px;
}
h6, h5, h4, h3, h2, h1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-bs-original-title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul {
padding-right: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: 0.5rem;
margin-right: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 0.875em;
}
mark {
padding: 0.2em;
background-color: #fcf8e3;
}
sub,
sup {
position: relative;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
a {
color: #0d6efd;
text-decoration: underline;
}
a:hover {
color: #0a58ca;
}
a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: inherit;
text-decoration: none;
}
pre,
code,
kbd,
samp {
font-family: var(--bs-font-monospace);
font-size: 1em;
direction: ltr ;
unicode-bidi: bidi-override;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
font-size: 0.875em;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: #d63384;
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.2rem 0.4rem;
font-size: 0.875em;
color: #fff;
background-color: #212529;
border-radius: 0.2rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
font-weight: 700;
}
figure {
margin: 0 0 1rem;
}
img,
svg {
vertical-align: middle;
}
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: #6c757d;
text-align: right;
}
th {
text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
label {
display: inline-block;
}
button {
border-radius: 0;
}
button:focus:not(:focus-visible) {
outline: 0;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
select {
text-transform: none;
}
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
select:disabled {
opacity: 1;
}
[list]::-webkit-calendar-picker-indicator {
display: none;
}
button,
[type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
button:not(:disabled),
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
::-moz-focus-inner {
padding: 0;
border-style: none;
}
textarea {
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
float: right;
width: 100%;
padding: 0;
margin-bottom: 0.5rem;
font-size: calc(1.275rem + 0.3vw);
line-height: inherit;
}
@media (min-width: 1200px) {
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: right;
}
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
[type=search] {
outline-offset: -2px;
-webkit-appearance: textfield;
}
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-color-swatch-wrapper {
padding: 0;
}
::-webkit-file-upload-button {
font: inherit;
}
::file-selector-button {
font: inherit;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
iframe {
border: 0;
}
summary {
display: list-item;
cursor: pointer;
}
progress {
vertical-align: baseline;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.rtl.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,118 +0,0 @@
//
// Base styles
//
.accordion-button {
position: relative;
display: flex;
align-items: center;
width: 100%;
padding: $accordion-button-padding-y $accordion-button-padding-x;
@include font-size($font-size-base);
color: $accordion-button-color;
text-align: left; // Reset button style
background-color: $accordion-button-bg;
border: 0;
@include border-radius(0);
overflow-anchor: none;
@include transition($accordion-transition);
&:not(.collapsed) {
color: $accordion-button-active-color;
background-color: $accordion-button-active-bg;
box-shadow: inset 0 ($accordion-border-width * -1) 0 $accordion-border-color;
&::after {
background-image: escape-svg($accordion-button-active-icon);
transform: $accordion-icon-transform;
}
}
// Accordion icon
&::after {
flex-shrink: 0;
width: $accordion-icon-width;
height: $accordion-icon-width;
margin-left: auto;
content: "";
background-image: escape-svg($accordion-button-icon);
background-repeat: no-repeat;
background-size: $accordion-icon-width;
@include transition($accordion-icon-transition);
}
&:hover {
z-index: 2;
}
&:focus {
z-index: 3;
border-color: $accordion-button-focus-border-color;
outline: 0;
box-shadow: $accordion-button-focus-box-shadow;
}
}
.accordion-header {
margin-bottom: 0;
}
.accordion-item {
background-color: $accordion-bg;
border: $accordion-border-width solid $accordion-border-color;
&:first-of-type {
@include border-top-radius($accordion-border-radius);
.accordion-button {
@include border-top-radius($accordion-inner-border-radius);
}
}
&:not(:first-of-type) {
border-top: 0;
}
// Only set a border-radius on the last item if the accordion is collapsed
&:last-of-type {
@include border-bottom-radius($accordion-border-radius);
.accordion-button {
&.collapsed {
@include border-bottom-radius($accordion-inner-border-radius);
}
}
.accordion-collapse {
@include border-bottom-radius($accordion-border-radius);
}
}
}
.accordion-body {
padding: $accordion-body-padding-y $accordion-body-padding-x;
}
// Flush accordion items
//
// Remove borders and border-radius to keep accordion items edge-to-edge.
.accordion-flush {
.accordion-collapse {
border-width: 0;
}
.accordion-item {
border-right: 0;
border-left: 0;
@include border-radius(0);
&:first-child { border-top: 0; }
&:last-child { border-bottom: 0; }
.accordion-button {
@include border-radius(0);
}
}
}

View File

@ -1,57 +0,0 @@
//
// Base styles
//
.alert {
position: relative;
padding: $alert-padding-y $alert-padding-x;
margin-bottom: $alert-margin-bottom;
border: $alert-border-width solid transparent;
@include border-radius($alert-border-radius);
}
// Headings for larger alerts
.alert-heading {
// Specified to prevent conflicts of changing $headings-color
color: inherit;
}
// Provide class for links that match alerts
.alert-link {
font-weight: $alert-link-font-weight;
}
// Dismissible alerts
//
// Expand the right padding and account for the close button's positioning.
.alert-dismissible {
padding-right: $alert-dismissible-padding-r;
// Adjust close link position
.btn-close {
position: absolute;
top: 0;
right: 0;
z-index: $stretched-link-z-index + 1;
padding: $alert-padding-y * 1.25 $alert-padding-x;
}
}
// scss-docs-start alert-modifiers
// Generate contextual modifier classes for colorizing the alert.
@each $state, $value in $theme-colors {
$alert-background: shift-color($value, $alert-bg-scale);
$alert-border: shift-color($value, $alert-border-scale);
$alert-color: shift-color($value, $alert-color-scale);
@if (contrast-ratio($alert-background, $alert-color) < $min-contrast-ratio) {
$alert-color: mix($value, color-contrast($alert-background), abs($alert-color-scale));
}
.alert-#{$state} {
@include alert-variant($alert-background, $alert-border, $alert-color);
}
}
// scss-docs-end alert-modifiers

View File

@ -1,29 +0,0 @@
// Base class
//
// Requires one of the contextual, color modifier classes for `color` and
// `background-color`.
.badge {
display: inline-block;
padding: $badge-padding-y $badge-padding-x;
@include font-size($badge-font-size);
font-weight: $badge-font-weight;
line-height: 1;
color: $badge-color;
text-align: center;
white-space: nowrap;
vertical-align: baseline;
@include border-radius($badge-border-radius);
@include gradient-bg();
// Empty badges collapse automatically
&:empty {
display: none;
}
}
// Quick fix for badges in buttons
.btn .badge {
position: relative;
top: -1px;
}

View File

@ -1,28 +0,0 @@
.breadcrumb {
display: flex;
flex-wrap: wrap;
padding: $breadcrumb-padding-y $breadcrumb-padding-x;
margin-bottom: $breadcrumb-margin-bottom;
@include font-size($breadcrumb-font-size);
list-style: none;
background-color: $breadcrumb-bg;
@include border-radius($breadcrumb-border-radius);
}
.breadcrumb-item {
// The separator between breadcrumbs (by default, a forward-slash: "/")
+ .breadcrumb-item {
padding-left: $breadcrumb-item-padding-x;
&::before {
float: left; // Suppress inline spacings and underlining of the separator
padding-right: $breadcrumb-item-padding-x;
color: $breadcrumb-divider-color;
content: var(--#{$variable-prefix}breadcrumb-divider, escape-svg($breadcrumb-divider)) #{"/* rtl:"} var(--#{$variable-prefix}breadcrumb-divider, escape-svg($breadcrumb-divider-flipped)) #{"*/"};
}
}
&.active {
color: $breadcrumb-active-color;
}
}

View File

@ -1,139 +0,0 @@
// Make the div behave like a button
.btn-group,
.btn-group-vertical {
position: relative;
display: inline-flex;
vertical-align: middle; // match .btn alignment given font-size hack above
> .btn {
position: relative;
flex: 1 1 auto;
}
// Bring the hover, focused, and "active" buttons to the front to overlay
// the borders properly
> .btn-check:checked + .btn,
> .btn-check:focus + .btn,
> .btn:hover,
> .btn:focus,
> .btn:active,
> .btn.active {
z-index: 1;
}
}
// Optional: Group multiple button groups together for a toolbar
.btn-toolbar {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
.input-group {
width: auto;
}
}
.btn-group {
// Prevent double borders when buttons are next to each other
> .btn:not(:first-child),
> .btn-group:not(:first-child) {
margin-left: -$btn-border-width;
}
// Reset rounded corners
> .btn:not(:last-child):not(.dropdown-toggle),
> .btn-group:not(:last-child) > .btn {
@include border-end-radius(0);
}
// The left radius should be 0 if the button is:
// - the "third or more" child
// - the second child and the previous element isn't `.btn-check` (making it the first child visually)
// - part of a btn-group which isn't the first child
> .btn:nth-child(n + 3),
> :not(.btn-check) + .btn,
> .btn-group:not(:first-child) > .btn {
@include border-start-radius(0);
}
}
// Sizing
//
// Remix the default button sizing classes into new ones for easier manipulation.
.btn-group-sm > .btn { @extend .btn-sm; }
.btn-group-lg > .btn { @extend .btn-lg; }
//
// Split button dropdowns
//
.dropdown-toggle-split {
padding-right: $btn-padding-x * .75;
padding-left: $btn-padding-x * .75;
&::after,
.dropup &::after,
.dropend &::after {
margin-left: 0;
}
.dropstart &::before {
margin-right: 0;
}
}
.btn-sm + .dropdown-toggle-split {
padding-right: $btn-padding-x-sm * .75;
padding-left: $btn-padding-x-sm * .75;
}
.btn-lg + .dropdown-toggle-split {
padding-right: $btn-padding-x-lg * .75;
padding-left: $btn-padding-x-lg * .75;
}
// The clickable button for toggling the menu
// Set the same inset shadow as the :active state
.btn-group.show .dropdown-toggle {
@include box-shadow($btn-active-box-shadow);
// Show no shadow for `.btn-link` since it has no other button styles.
&.btn-link {
@include box-shadow(none);
}
}
//
// Vertical button groups
//
.btn-group-vertical {
flex-direction: column;
align-items: flex-start;
justify-content: center;
> .btn,
> .btn-group {
width: 100%;
}
> .btn:not(:first-child),
> .btn-group:not(:first-child) {
margin-top: -$btn-border-width;
}
// Reset rounded corners
> .btn:not(:last-child):not(.dropdown-toggle),
> .btn-group:not(:last-child) > .btn {
@include border-bottom-radius(0);
}
> .btn ~ .btn,
> .btn-group:not(:first-child) > .btn {
@include border-top-radius(0);
}
}

View File

@ -1,111 +0,0 @@
//
// Base styles
//
.btn {
display: inline-block;
font-family: $btn-font-family;
font-weight: $btn-font-weight;
line-height: $btn-line-height;
color: $body-color;
text-align: center;
text-decoration: if($link-decoration == none, null, none);
white-space: $btn-white-space;
vertical-align: middle;
cursor: if($enable-button-pointers, pointer, null);
user-select: none;
background-color: transparent;
border: $btn-border-width solid transparent;
@include button-size($btn-padding-y, $btn-padding-x, $btn-font-size, $btn-border-radius);
@include transition($btn-transition);
&:hover {
color: $body-color;
text-decoration: if($link-hover-decoration == underline, none, null);
}
.btn-check:focus + &,
&:focus {
outline: 0;
box-shadow: $btn-focus-box-shadow;
}
.btn-check:checked + &,
.btn-check:active + &,
&:active,
&.active {
@include box-shadow($btn-active-box-shadow);
&:focus {
@include box-shadow($btn-focus-box-shadow, $btn-active-box-shadow);
}
}
&:disabled,
&.disabled,
fieldset:disabled & {
pointer-events: none;
opacity: $btn-disabled-opacity;
@include box-shadow(none);
}
}
//
// Alternate buttons
//
// scss-docs-start btn-variant-loops
@each $color, $value in $theme-colors {
.btn-#{$color} {
@include button-variant($value, $value);
}
}
@each $color, $value in $theme-colors {
.btn-outline-#{$color} {
@include button-outline-variant($value);
}
}
// scss-docs-end btn-variant-loops
//
// Link buttons
//
// Make a button look and behave like a link
.btn-link {
font-weight: $font-weight-normal;
color: $btn-link-color;
text-decoration: $link-decoration;
&:hover {
color: $btn-link-hover-color;
text-decoration: $link-hover-decoration;
}
&:focus {
text-decoration: $link-hover-decoration;
}
&:disabled,
&.disabled {
color: $btn-link-disabled-color;
}
// No need for an active state here
}
//
// Button Sizes
//
.btn-lg {
@include button-size($btn-padding-y-lg, $btn-padding-x-lg, $btn-font-size-lg, $btn-border-radius-lg);
}
.btn-sm {
@include button-size($btn-padding-y-sm, $btn-padding-x-sm, $btn-font-size-sm, $btn-border-radius-sm);
}

View File

@ -1,216 +0,0 @@
//
// Base styles
//
.card {
position: relative;
display: flex;
flex-direction: column;
min-width: 0; // See https://github.com/twbs/bootstrap/pull/22740#issuecomment-305868106
height: $card-height;
word-wrap: break-word;
background-color: $card-bg;
background-clip: border-box;
border: $card-border-width solid $card-border-color;
@include border-radius($card-border-radius);
@include box-shadow($card-box-shadow);
> hr {
margin-right: 0;
margin-left: 0;
}
> .list-group {
border-top: inherit;
border-bottom: inherit;
&:first-child {
border-top-width: 0;
@include border-top-radius($card-inner-border-radius);
}
&:last-child {
border-bottom-width: 0;
@include border-bottom-radius($card-inner-border-radius);
}
}
// Due to specificity of the above selector (`.card > .list-group`), we must
// use a child selector here to prevent double borders.
> .card-header + .list-group,
> .list-group + .card-footer {
border-top: 0;
}
}
.card-body {
// Enable `flex-grow: 1` for decks and groups so that card blocks take up
// as much space as possible, ensuring footers are aligned to the bottom.
flex: 1 1 auto;
padding: $card-spacer-y $card-spacer-x;
color: $card-color;
}
.card-title {
margin-bottom: $card-title-spacer-y;
}
.card-subtitle {
margin-top: -$card-title-spacer-y * .5;
margin-bottom: 0;
}
.card-text:last-child {
margin-bottom: 0;
}
.card-link {
&:hover {
text-decoration: if($link-hover-decoration == underline, none, null);
}
+ .card-link {
margin-left: $card-spacer-x;
}
}
//
// Optional textual caps
//
.card-header {
padding: $card-cap-padding-y $card-cap-padding-x;
margin-bottom: 0; // Removes the default margin-bottom of <hN>
color: $card-cap-color;
background-color: $card-cap-bg;
border-bottom: $card-border-width solid $card-border-color;
&:first-child {
@include border-radius($card-inner-border-radius $card-inner-border-radius 0 0);
}
}
.card-footer {
padding: $card-cap-padding-y $card-cap-padding-x;
color: $card-cap-color;
background-color: $card-cap-bg;
border-top: $card-border-width solid $card-border-color;
&:last-child {
@include border-radius(0 0 $card-inner-border-radius $card-inner-border-radius);
}
}
//
// Header navs
//
.card-header-tabs {
margin-right: -$card-cap-padding-x * .5;
margin-bottom: -$card-cap-padding-y;
margin-left: -$card-cap-padding-x * .5;
border-bottom: 0;
@if $nav-tabs-link-active-bg != $card-bg {
.nav-link.active {
background-color: $card-bg;
border-bottom-color: $card-bg;
}
}
}
.card-header-pills {
margin-right: -$card-cap-padding-x * .5;
margin-left: -$card-cap-padding-x * .5;
}
// Card image
.card-img-overlay {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
padding: $card-img-overlay-padding;
@include border-radius($card-inner-border-radius);
}
.card-img,
.card-img-top,
.card-img-bottom {
width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch
}
.card-img,
.card-img-top {
@include border-top-radius($card-inner-border-radius);
}
.card-img,
.card-img-bottom {
@include border-bottom-radius($card-inner-border-radius);
}
//
// Card groups
//
.card-group {
// The child selector allows nested `.card` within `.card-group`
// to display properly.
> .card {
margin-bottom: $card-group-margin;
}
@include media-breakpoint-up(sm) {
display: flex;
flex-flow: row wrap;
// The child selector allows nested `.card` within `.card-group`
// to display properly.
> .card {
// Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4
flex: 1 0 0%;
margin-bottom: 0;
+ .card {
margin-left: 0;
border-left: 0;
}
// Handle rounded corners
@if $enable-rounded {
&:not(:last-child) {
@include border-end-radius(0);
.card-img-top,
.card-header {
// stylelint-disable-next-line property-disallowed-list
border-top-right-radius: 0;
}
.card-img-bottom,
.card-footer {
// stylelint-disable-next-line property-disallowed-list
border-bottom-right-radius: 0;
}
}
&:not(:first-child) {
@include border-start-radius(0);
.card-img-top,
.card-header {
// stylelint-disable-next-line property-disallowed-list
border-top-left-radius: 0;
}
.card-img-bottom,
.card-footer {
// stylelint-disable-next-line property-disallowed-list
border-bottom-left-radius: 0;
}
}
}
}
}
}

View File

@ -1,229 +0,0 @@
// Notes on the classes:
//
// 1. .carousel.pointer-event should ideally be pan-y (to allow for users to scroll vertically)
// even when their scroll action started on a carousel, but for compatibility (with Firefox)
// we're preventing all actions instead
// 2. The .carousel-item-start and .carousel-item-end is used to indicate where
// the active slide is heading.
// 3. .active.carousel-item is the current slide.
// 4. .active.carousel-item-start and .active.carousel-item-end is the current
// slide in its in-transition state. Only one of these occurs at a time.
// 5. .carousel-item-next.carousel-item-start and .carousel-item-prev.carousel-item-end
// is the upcoming slide in transition.
.carousel {
position: relative;
}
.carousel.pointer-event {
touch-action: pan-y;
}
.carousel-inner {
position: relative;
width: 100%;
overflow: hidden;
@include clearfix();
}
.carousel-item {
position: relative;
display: none;
float: left;
width: 100%;
margin-right: -100%;
backface-visibility: hidden;
@include transition($carousel-transition);
}
.carousel-item.active,
.carousel-item-next,
.carousel-item-prev {
display: block;
}
/* rtl:begin:ignore */
.carousel-item-next:not(.carousel-item-start),
.active.carousel-item-end {
transform: translateX(100%);
}
.carousel-item-prev:not(.carousel-item-end),
.active.carousel-item-start {
transform: translateX(-100%);
}
/* rtl:end:ignore */
//
// Alternate transitions
//
.carousel-fade {
.carousel-item {
opacity: 0;
transition-property: opacity;
transform: none;
}
.carousel-item.active,
.carousel-item-next.carousel-item-start,
.carousel-item-prev.carousel-item-end {
z-index: 1;
opacity: 1;
}
.active.carousel-item-start,
.active.carousel-item-end {
z-index: 0;
opacity: 0;
@include transition(opacity 0s $carousel-transition-duration);
}
}
//
// Left/right controls for nav
//
.carousel-control-prev,
.carousel-control-next {
position: absolute;
top: 0;
bottom: 0;
z-index: 1;
// Use flex for alignment (1-3)
display: flex; // 1. allow flex styles
align-items: center; // 2. vertically center contents
justify-content: center; // 3. horizontally center contents
width: $carousel-control-width;
padding: 0;
color: $carousel-control-color;
text-align: center;
background: none;
border: 0;
opacity: $carousel-control-opacity;
@include transition($carousel-control-transition);
// Hover/focus state
&:hover,
&:focus {
color: $carousel-control-color;
text-decoration: none;
outline: 0;
opacity: $carousel-control-hover-opacity;
}
}
.carousel-control-prev {
left: 0;
background-image: if($enable-gradients, linear-gradient(90deg, rgba($black, .25), rgba($black, .001)), null);
}
.carousel-control-next {
right: 0;
background-image: if($enable-gradients, linear-gradient(270deg, rgba($black, .25), rgba($black, .001)), null);
}
// Icons for within
.carousel-control-prev-icon,
.carousel-control-next-icon {
display: inline-block;
width: $carousel-control-icon-width;
height: $carousel-control-icon-width;
background-repeat: no-repeat;
background-position: 50%;
background-size: 100% 100%;
}
/* rtl:options: {
"autoRename": true,
"stringMap":[ {
"name" : "prev-next",
"search" : "prev",
"replace" : "next"
} ]
} */
.carousel-control-prev-icon {
background-image: escape-svg($carousel-control-prev-icon-bg);
}
.carousel-control-next-icon {
background-image: escape-svg($carousel-control-next-icon-bg);
}
// Optional indicator pips/controls
//
// Add a container (such as a list) with the following class and add an item (ideally a focusable control,
// like a button) with data-bs-target for each slide your carousel holds.
.carousel-indicators {
position: absolute;
right: 0;
bottom: 0;
left: 0;
z-index: 2;
display: flex;
justify-content: center;
padding: 0;
// Use the .carousel-control's width as margin so we don't overlay those
margin-right: $carousel-control-width;
margin-bottom: 1rem;
margin-left: $carousel-control-width;
list-style: none;
[data-bs-target] {
box-sizing: content-box;
flex: 0 1 auto;
width: $carousel-indicator-width;
height: $carousel-indicator-height;
padding: 0;
margin-right: $carousel-indicator-spacer;
margin-left: $carousel-indicator-spacer;
text-indent: -999px;
cursor: pointer;
background-color: $carousel-indicator-active-bg;
background-clip: padding-box;
border: 0;
// Use transparent borders to increase the hit area by 10px on top and bottom.
border-top: $carousel-indicator-hit-area-height solid transparent;
border-bottom: $carousel-indicator-hit-area-height solid transparent;
opacity: $carousel-indicator-opacity;
@include transition($carousel-indicator-transition);
}
.active {
opacity: $carousel-indicator-active-opacity;
}
}
// Optional captions
//
//
.carousel-caption {
position: absolute;
right: (100% - $carousel-caption-width) * .5;
bottom: $carousel-caption-spacer;
left: (100% - $carousel-caption-width) * .5;
padding-top: $carousel-caption-padding-y;
padding-bottom: $carousel-caption-padding-y;
color: $carousel-caption-color;
text-align: center;
}
// Dark mode carousel
.carousel-dark {
.carousel-control-prev-icon,
.carousel-control-next-icon {
filter: $carousel-dark-control-icon-filter;
}
.carousel-indicators [data-bs-target] {
background-color: $carousel-dark-indicator-active-bg;
}
.carousel-caption {
color: $carousel-dark-caption-color;
}
}

View File

@ -1,40 +0,0 @@
// transparent background and border properties included for button version.
// iOS requires the button element instead of an anchor tag.
// If you want the anchor version, it requires `href="#"`.
// See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile
.btn-close {
box-sizing: content-box;
width: $btn-close-width;
height: $btn-close-height;
padding: $btn-close-padding-y $btn-close-padding-x;
color: $btn-close-color;
background: transparent escape-svg($btn-close-bg) center / $btn-close-width auto no-repeat; // include transparent for button elements
border: 0; // for button elements
@include border-radius();
opacity: $btn-close-opacity;
// Override <a>'s hover style
&:hover {
color: $btn-close-color;
text-decoration: none;
opacity: $btn-close-hover-opacity;
}
&:focus {
outline: 0;
box-shadow: $btn-close-focus-shadow;
opacity: $btn-close-focus-opacity;
}
&:disabled,
&.disabled {
pointer-events: none;
user-select: none;
opacity: $btn-close-disabled-opacity;
}
}
.btn-close-white {
filter: $btn-close-white-filter;
}

View File

@ -1,41 +0,0 @@
// Container widths
//
// Set the container width, and override it for fixed navbars in media queries.
@if $enable-grid-classes {
// Single container class with breakpoint max-widths
.container,
// 100% wide container at all breakpoints
.container-fluid {
@include make-container();
}
// Responsive containers that are 100% wide until a breakpoint
@each $breakpoint, $container-max-width in $container-max-widths {
.container-#{$breakpoint} {
@extend .container-fluid;
}
@include media-breakpoint-up($breakpoint, $grid-breakpoints) {
%responsive-container-#{$breakpoint} {
max-width: $container-max-width;
}
// Extend each breakpoint which is smaller or equal to the current breakpoint
$extend-breakpoint: true;
@each $name, $width in $grid-breakpoints {
@if ($extend-breakpoint) {
.container#{breakpoint-infix($name, $grid-breakpoints)} {
@extend %responsive-container-#{$breakpoint};
}
// Once the current breakpoint is reached, stop extending
@if ($breakpoint == $name) {
$extend-breakpoint: false;
}
}
}
}
}
}

View File

@ -1,240 +0,0 @@
// The dropdown wrapper (`<div>`)
.dropup,
.dropend,
.dropdown,
.dropstart {
position: relative;
}
.dropdown-toggle {
white-space: nowrap;
// Generate the caret automatically
@include caret();
}
// The dropdown menu
.dropdown-menu {
position: absolute;
z-index: $zindex-dropdown;
display: none; // none by default, but block on "open" of the menu
min-width: $dropdown-min-width;
padding: $dropdown-padding-y $dropdown-padding-x;
margin: 0; // Override default margin of ul
@include font-size($dropdown-font-size);
color: $dropdown-color;
text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)
list-style: none;
background-color: $dropdown-bg;
background-clip: padding-box;
border: $dropdown-border-width solid $dropdown-border-color;
@include border-radius($dropdown-border-radius);
@include box-shadow($dropdown-box-shadow);
&[data-bs-popper] {
top: 100%;
left: 0;
margin-top: $dropdown-spacer;
}
}
// scss-docs-start responsive-breakpoints
// We deliberately hardcode the `bs-` prefix because we check
// this custom property in JS to determine Popper's positioning
@each $breakpoint in map-keys($grid-breakpoints) {
@include media-breakpoint-up($breakpoint) {
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);
.dropdown-menu#{$infix}-start {
--bs-position: start;
&[data-bs-popper] {
right: auto;
left: 0;
}
}
.dropdown-menu#{$infix}-end {
--bs-position: end;
&[data-bs-popper] {
right: 0;
left: auto;
}
}
}
}
// scss-docs-end responsive-breakpoints
// Allow for dropdowns to go bottom up (aka, dropup-menu)
// Just add .dropup after the standard .dropdown class and you're set.
.dropup {
.dropdown-menu[data-bs-popper] {
top: auto;
bottom: 100%;
margin-top: 0;
margin-bottom: $dropdown-spacer;
}
.dropdown-toggle {
@include caret(up);
}
}
.dropend {
.dropdown-menu[data-bs-popper] {
top: 0;
right: auto;
left: 100%;
margin-top: 0;
margin-left: $dropdown-spacer;
}
.dropdown-toggle {
@include caret(end);
&::after {
vertical-align: 0;
}
}
}
.dropstart {
.dropdown-menu[data-bs-popper] {
top: 0;
right: 100%;
left: auto;
margin-top: 0;
margin-right: $dropdown-spacer;
}
.dropdown-toggle {
@include caret(start);
&::before {
vertical-align: 0;
}
}
}
// Dividers (basically an `<hr>`) within the dropdown
.dropdown-divider {
height: 0;
margin: $dropdown-divider-margin-y 0;
overflow: hidden;
border-top: 1px solid $dropdown-divider-bg;
}
// Links, buttons, and more within the dropdown menu
//
// `<button>`-specific styles are denoted with `// For <button>s`
.dropdown-item {
display: block;
width: 100%; // For `<button>`s
padding: $dropdown-item-padding-y $dropdown-item-padding-x;
clear: both;
font-weight: $font-weight-normal;
color: $dropdown-link-color;
text-align: inherit; // For `<button>`s
text-decoration: if($link-decoration == none, null, none);
white-space: nowrap; // prevent links from randomly breaking onto new lines
background-color: transparent; // For `<button>`s
border: 0; // For `<button>`s
// Prevent dropdown overflow if there's no padding
// See https://github.com/twbs/bootstrap/pull/27703
@if $dropdown-padding-y == 0 {
&:first-child {
@include border-top-radius($dropdown-inner-border-radius);
}
&:last-child {
@include border-bottom-radius($dropdown-inner-border-radius);
}
}
&:hover,
&:focus {
color: $dropdown-link-hover-color;
text-decoration: if($link-hover-decoration == underline, none, null);
@include gradient-bg($dropdown-link-hover-bg);
}
&.active,
&:active {
color: $dropdown-link-active-color;
text-decoration: none;
@include gradient-bg($dropdown-link-active-bg);
}
&.disabled,
&:disabled {
color: $dropdown-link-disabled-color;
pointer-events: none;
background-color: transparent;
// Remove CSS gradients if they're enabled
background-image: if($enable-gradients, none, null);
}
}
.dropdown-menu.show {
display: block;
}
// Dropdown section headers
.dropdown-header {
display: block;
padding: $dropdown-header-padding;
margin-bottom: 0; // for use with heading elements
@include font-size($font-size-sm);
color: $dropdown-header-color;
white-space: nowrap; // as with > li > a
}
// Dropdown text
.dropdown-item-text {
display: block;
padding: $dropdown-item-padding-y $dropdown-item-padding-x;
color: $dropdown-link-color;
}
// Dark dropdowns
.dropdown-menu-dark {
color: $dropdown-dark-color;
background-color: $dropdown-dark-bg;
border-color: $dropdown-dark-border-color;
@include box-shadow($dropdown-dark-box-shadow);
.dropdown-item {
color: $dropdown-dark-link-color;
&:hover,
&:focus {
color: $dropdown-dark-link-hover-color;
@include gradient-bg($dropdown-dark-link-hover-bg);
}
&.active,
&:active {
color: $dropdown-dark-link-active-color;
@include gradient-bg($dropdown-dark-link-active-bg);
}
&.disabled,
&:disabled {
color: $dropdown-dark-link-disabled-color;
}
}
.dropdown-divider {
border-color: $dropdown-dark-divider-bg;
}
.dropdown-item-text {
color: $dropdown-dark-link-color;
}
.dropdown-header {
color: $dropdown-dark-header-color;
}
}

View File

@ -1,9 +0,0 @@
@import "forms/labels";
@import "forms/form-text";
@import "forms/form-control";
@import "forms/form-select";
@import "forms/form-check";
@import "forms/form-range";
@import "forms/floating-labels";
@import "forms/input-group";
@import "forms/validation";

View File

@ -1,302 +0,0 @@
// Bootstrap functions
//
// Utility mixins and functions for evaluating source code across our variables, maps, and mixins.
// Ascending
// Used to evaluate Sass maps like our grid breakpoints.
@mixin _assert-ascending($map, $map-name) {
$prev-key: null;
$prev-num: null;
@each $key, $num in $map {
@if $prev-num == null or unit($num) == "%" or unit($prev-num) == "%" {
// Do nothing
} @else if not comparable($prev-num, $num) {
@warn "Potentially invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} whose unit makes it incomparable to #{$prev-num}, the value of the previous key '#{$prev-key}' !";
} @else if $prev-num >= $num {
@warn "Invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} which isn't greater than #{$prev-num}, the value of the previous key '#{$prev-key}' !";
}
$prev-key: $key;
$prev-num: $num;
}
}
// Starts at zero
// Used to ensure the min-width of the lowest breakpoint starts at 0.
@mixin _assert-starts-at-zero($map, $map-name: "$grid-breakpoints") {
@if length($map) > 0 {
$values: map-values($map);
$first-value: nth($values, 1);
@if $first-value != 0 {
@warn "First breakpoint in #{$map-name} must start at 0, but starts at #{$first-value}.";
}
}
}
// Colors
@function to-rgb($value) {
@return red($value), green($value), blue($value);
}
// stylelint-disable scss/dollar-variable-pattern
@function rgba-css-var($identifier, $target) {
@if $identifier == "body" and $target == "bg" {
@return rgba(var(--#{$variable-prefix}#{$identifier}-bg-rgb), var(--#{$variable-prefix}#{$target}-opacity));
} @if $identifier == "body" and $target == "text" {
@return rgba(var(--#{$variable-prefix}#{$identifier}-color-rgb), var(--#{$variable-prefix}#{$target}-opacity));
} @else {
@return rgba(var(--#{$variable-prefix}#{$identifier}-rgb), var(--#{$variable-prefix}#{$target}-opacity));
}
}
@function map-loop($map, $func, $args...) {
$_map: ();
@each $key, $value in $map {
// allow to pass the $key and $value of the map as an function argument
$_args: ();
@each $arg in $args {
$_args: append($_args, if($arg == "$key", $key, if($arg == "$value", $value, $arg)));
}
$_map: map-merge($_map, ($key: call(get-function($func), $_args...)));
}
@return $_map;
}
// stylelint-enable scss/dollar-variable-pattern
@function varify($list) {
$result: null;
@each $entry in $list {
$result: append($result, var(--#{$variable-prefix}#{$entry}), space);
}
@return $result;
}
// Internal Bootstrap function to turn maps into its negative variant.
// It prefixes the keys with `n` and makes the value negative.
@function negativify-map($map) {
$result: ();
@each $key, $value in $map {
@if $key != 0 {
$result: map-merge($result, ("n" + $key: (-$value)));
}
}
@return $result;
}
// Get multiple keys from a sass map
@function map-get-multiple($map, $values) {
$result: ();
@each $key, $value in $map {
@if (index($values, $key) != null) {
$result: map-merge($result, ($key: $value));
}
}
@return $result;
}
// Merge multiple maps
@function map-merge-multiple($maps...) {
$merged-maps: ();
@each $map in $maps {
$merged-maps: map-merge($merged-maps, $map);
}
@return $merged-maps;
}
// Replace `$search` with `$replace` in `$string`
// Used on our SVG icon backgrounds for custom forms.
//
// @author Hugo Giraudel
// @param {String} $string - Initial string
// @param {String} $search - Substring to replace
// @param {String} $replace ('') - New value
// @return {String} - Updated string
@function str-replace($string, $search, $replace: "") {
$index: str-index($string, $search);
@if $index {
@return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
}
@return $string;
}
// See https://codepen.io/kevinweber/pen/dXWoRw
//
// Requires the use of quotes around data URIs.
@function escape-svg($string) {
@if str-index($string, "data:image/svg+xml") {
@each $char, $encoded in $escaped-characters {
// Do not escape the url brackets
@if str-index($string, "url(") == 1 {
$string: url("#{str-replace(str-slice($string, 6, -3), $char, $encoded)}");
} @else {
$string: str-replace($string, $char, $encoded);
}
}
}
@return $string;
}
// Color contrast
// See https://github.com/twbs/bootstrap/pull/30168
// A list of pre-calculated numbers of pow(divide((divide($value, 255) + .055), 1.055), 2.4). (from 0 to 255)
// stylelint-disable-next-line scss/dollar-variable-default, scss/dollar-variable-pattern
$_luminance-list: .0008 .001 .0011 .0013 .0015 .0017 .002 .0022 .0025 .0027 .003 .0033 .0037 .004 .0044 .0048 .0052 .0056 .006 .0065 .007 .0075 .008 .0086 .0091 .0097 .0103 .011 .0116 .0123 .013 .0137 .0144 .0152 .016 .0168 .0176 .0185 .0194 .0203 .0212 .0222 .0232 .0242 .0252 .0262 .0273 .0284 .0296 .0307 .0319 .0331 .0343 .0356 .0369 .0382 .0395 .0409 .0423 .0437 .0452 .0467 .0482 .0497 .0513 .0529 .0545 .0561 .0578 .0595 .0612 .063 .0648 .0666 .0685 .0704 .0723 .0742 .0762 .0782 .0802 .0823 .0844 .0865 .0887 .0908 .0931 .0953 .0976 .0999 .1022 .1046 .107 .1095 .1119 .1144 .117 .1195 .1221 .1248 .1274 .1301 .1329 .1356 .1384 .1413 .1441 .147 .15 .1529 .1559 .159 .162 .1651 .1683 .1714 .1746 .1779 .1812 .1845 .1878 .1912 .1946 .1981 .2016 .2051 .2086 .2122 .2159 .2195 .2232 .227 .2307 .2346 .2384 .2423 .2462 .2502 .2542 .2582 .2623 .2664 .2705 .2747 .2789 .2831 .2874 .2918 .2961 .3005 .305 .3095 .314 .3185 .3231 .3278 .3325 .3372 .3419 .3467 .3515 .3564 .3613 .3663 .3712 .3763 .3813 .3864 .3916 .3968 .402 .4072 .4125 .4179 .4233 .4287 .4342 .4397 .4452 .4508 .4564 .4621 .4678 .4735 .4793 .4851 .491 .4969 .5029 .5089 .5149 .521 .5271 .5333 .5395 .5457 .552 .5583 .5647 .5711 .5776 .5841 .5906 .5972 .6038 .6105 .6172 .624 .6308 .6376 .6445 .6514 .6584 .6654 .6724 .6795 .6867 .6939 .7011 .7084 .7157 .7231 .7305 .7379 .7454 .7529 .7605 .7682 .7758 .7835 .7913 .7991 .807 .8148 .8228 .8308 .8388 .8469 .855 .8632 .8714 .8796 .8879 .8963 .9047 .9131 .9216 .9301 .9387 .9473 .956 .9647 .9734 .9823 .9911 1;
@function color-contrast($background, $color-contrast-dark: $color-contrast-dark, $color-contrast-light: $color-contrast-light, $min-contrast-ratio: $min-contrast-ratio) {
$foregrounds: $color-contrast-light, $color-contrast-dark, $white, $black;
$max-ratio: 0;
$max-ratio-color: null;
@each $color in $foregrounds {
$contrast-ratio: contrast-ratio($background, $color);
@if $contrast-ratio > $min-contrast-ratio {
@return $color;
} @else if $contrast-ratio > $max-ratio {
$max-ratio: $contrast-ratio;
$max-ratio-color: $color;
}
}
@warn "Found no color leading to #{$min-contrast-ratio}:1 contrast ratio against #{$background}...";
@return $max-ratio-color;
}
@function contrast-ratio($background, $foreground: $color-contrast-light) {
$l1: luminance($background);
$l2: luminance(opaque($background, $foreground));
@return if($l1 > $l2, divide($l1 + .05, $l2 + .05), divide($l2 + .05, $l1 + .05));
}
// Return WCAG2.0 relative luminance
// See https://www.w3.org/WAI/GL/wiki/Relative_luminance
// See https://www.w3.org/TR/WCAG20-TECHS/G17.html#G17-tests
@function luminance($color) {
$rgb: (
"r": red($color),
"g": green($color),
"b": blue($color)
);
@each $name, $value in $rgb {
$value: if(divide($value, 255) < .03928, divide(divide($value, 255), 12.92), nth($_luminance-list, $value + 1));
$rgb: map-merge($rgb, ($name: $value));
}
@return (map-get($rgb, "r") * .2126) + (map-get($rgb, "g") * .7152) + (map-get($rgb, "b") * .0722);
}
// Return opaque color
// opaque(#fff, rgba(0, 0, 0, .5)) => #808080
@function opaque($background, $foreground) {
@return mix(rgba($foreground, 1), $background, opacity($foreground) * 100);
}
// scss-docs-start color-functions
// Tint a color: mix a color with white
@function tint-color($color, $weight) {
@return mix(white, $color, $weight);
}
// Shade a color: mix a color with black
@function shade-color($color, $weight) {
@return mix(black, $color, $weight);
}
// Shade the color if the weight is positive, else tint it
@function shift-color($color, $weight) {
@return if($weight > 0, shade-color($color, $weight), tint-color($color, -$weight));
}
// scss-docs-end color-functions
// Return valid calc
@function add($value1, $value2, $return-calc: true) {
@if $value1 == null {
@return $value2;
}
@if $value2 == null {
@return $value1;
}
@if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) {
@return $value1 + $value2;
}
@return if($return-calc == true, calc(#{$value1} + #{$value2}), $value1 + unquote(" + ") + $value2);
}
@function subtract($value1, $value2, $return-calc: true) {
@if $value1 == null and $value2 == null {
@return null;
}
@if $value1 == null {
@return -$value2;
}
@if $value2 == null {
@return $value1;
}
@if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) {
@return $value1 - $value2;
}
@if type-of($value2) != number {
$value2: unquote("(") + $value2 + unquote(")");
}
@return if($return-calc == true, calc(#{$value1} - #{$value2}), $value1 + unquote(" - ") + $value2);
}
@function divide($dividend, $divisor, $precision: 10) {
$sign: if($dividend > 0 and $divisor > 0 or $dividend < 0 and $divisor < 0, 1, -1);
$dividend: abs($dividend);
$divisor: abs($divisor);
@if $dividend == 0 {
@return 0;
}
@if $divisor == 0 {
@error "Cannot divide by 0";
}
$remainder: $dividend;
$result: 0;
$factor: 10;
@while ($remainder > 0 and $precision >= 0) {
$quotient: 0;
@while ($remainder >= $divisor) {
$remainder: $remainder - $divisor;
$quotient: $quotient + 1;
}
$result: $result * 10 + $quotient;
$factor: $factor * .1;
$remainder: $remainder * 10;
$precision: $precision - 1;
@if ($precision < 0 and $remainder >= $divisor * 5) {
$result: $result + 1;
}
}
$result: $result * $factor * $sign;
$dividend-unit: unit($dividend);
$divisor-unit: unit($divisor);
$unit-map: (
"px": 1px,
"rem": 1rem,
"em": 1em,
"%": 1%
);
@if ($dividend-unit != $divisor-unit and map-has-key($unit-map, $dividend-unit)) {
$result: $result * map-get($unit-map, $dividend-unit);
}
@return $result;
}

View File

@ -1,33 +0,0 @@
// Row
//
// Rows contain your columns.
@if $enable-grid-classes {
.row {
@include make-row();
> * {
@include make-col-ready();
}
}
}
@if $enable-cssgrid {
.grid {
display: grid;
grid-template-rows: repeat(var(--#{$variable-prefix}rows, 1), 1fr);
grid-template-columns: repeat(var(--#{$variable-prefix}columns, #{$grid-columns}), 1fr);
gap: var(--#{$variable-prefix}gap, #{$grid-gutter-width});
@include make-cssgrid();
}
}
// Columns
//
// Common styles for small and large grid columns
@if $enable-grid-classes {
@include make-grid-columns();
}

View File

@ -1,9 +0,0 @@
@import "helpers/clearfix";
@import "helpers/colored-links";
@import "helpers/ratio";
@import "helpers/position";
@import "helpers/stacks";
@import "helpers/visually-hidden";
@import "helpers/stretched-link";
@import "helpers/text-truncation";
@import "helpers/vr";

View File

@ -1,42 +0,0 @@
// Responsive images (ensure images don't scale beyond their parents)
//
// This is purposefully opt-in via an explicit class rather than being the default for all `<img>`s.
// We previously tried the "images are responsive by default" approach in Bootstrap v2,
// and abandoned it in Bootstrap v3 because it breaks lots of third-party widgets (including Google Maps)
// which weren't expecting the images within themselves to be involuntarily resized.
// See also https://github.com/twbs/bootstrap/issues/18178
.img-fluid {
@include img-fluid();
}
// Image thumbnails
.img-thumbnail {
padding: $thumbnail-padding;
background-color: $thumbnail-bg;
border: $thumbnail-border-width solid $thumbnail-border-color;
@include border-radius($thumbnail-border-radius);
@include box-shadow($thumbnail-box-shadow);
// Keep them at most 100% wide
@include img-fluid();
}
//
// Figures
//
.figure {
// Ensures the caption's text aligns with the image.
display: inline-block;
}
.figure-img {
margin-bottom: $spacer * .5;
line-height: 1;
}
.figure-caption {
@include font-size($figure-caption-font-size);
color: $figure-caption-color;
}

View File

@ -1,174 +0,0 @@
// Base class
//
// Easily usable on <ul>, <ol>, or <div>.
.list-group {
display: flex;
flex-direction: column;
// No need to set list-style: none; since .list-group-item is block level
padding-left: 0; // reset padding because ul and ol
margin-bottom: 0;
@include border-radius($list-group-border-radius);
}
.list-group-numbered {
list-style-type: none;
counter-reset: section;
> li::before {
// Increments only this instance of the section counter
content: counters(section, ".") ". ";
counter-increment: section;
}
}
// Interactive list items
//
// Use anchor or button elements instead of `li`s or `div`s to create interactive
// list items. Includes an extra `.active` modifier class for selected items.
.list-group-item-action {
width: 100%; // For `<button>`s (anchors become 100% by default though)
color: $list-group-action-color;
text-align: inherit; // For `<button>`s (anchors inherit)
// Hover state
&:hover,
&:focus {
z-index: 1; // Place hover/focus items above their siblings for proper border styling
color: $list-group-action-hover-color;
text-decoration: none;
background-color: $list-group-hover-bg;
}
&:active {
color: $list-group-action-active-color;
background-color: $list-group-action-active-bg;
}
}
// Individual list items
//
// Use on `li`s or `div`s within the `.list-group` parent.
.list-group-item {
position: relative;
display: block;
padding: $list-group-item-padding-y $list-group-item-padding-x;
color: $list-group-color;
text-decoration: if($link-decoration == none, null, none);
background-color: $list-group-bg;
border: $list-group-border-width solid $list-group-border-color;
&:first-child {
@include border-top-radius(inherit);
}
&:last-child {
@include border-bottom-radius(inherit);
}
&.disabled,
&:disabled {
color: $list-group-disabled-color;
pointer-events: none;
background-color: $list-group-disabled-bg;
}
// Include both here for `<a>`s and `<button>`s
&.active {
z-index: 2; // Place active items above their siblings for proper border styling
color: $list-group-active-color;
background-color: $list-group-active-bg;
border-color: $list-group-active-border-color;
}
& + & {
border-top-width: 0;
&.active {
margin-top: -$list-group-border-width;
border-top-width: $list-group-border-width;
}
}
}
// Horizontal
//
// Change the layout of list group items from vertical (default) to horizontal.
@each $breakpoint in map-keys($grid-breakpoints) {
@include media-breakpoint-up($breakpoint) {
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);
.list-group-horizontal#{$infix} {
flex-direction: row;
> .list-group-item {
&:first-child {
@include border-bottom-start-radius($list-group-border-radius);
@include border-top-end-radius(0);
}
&:last-child {
@include border-top-end-radius($list-group-border-radius);
@include border-bottom-start-radius(0);
}
&.active {
margin-top: 0;
}
+ .list-group-item {
border-top-width: $list-group-border-width;
border-left-width: 0;
&.active {
margin-left: -$list-group-border-width;
border-left-width: $list-group-border-width;
}
}
}
}
}
}
// Flush list items
//
// Remove borders and border-radius to keep list group items edge-to-edge. Most
// useful within other components (e.g., cards).
.list-group-flush {
@include border-radius(0);
> .list-group-item {
border-width: 0 0 $list-group-border-width;
&:last-child {
border-bottom-width: 0;
}
}
}
// scss-docs-start list-group-modifiers
// List group contextual variants
//
// Add modifier classes to change text and background color on individual items.
// Organizationally, this must come after the `:hover` states.
@each $state, $value in $theme-colors {
$list-group-variant-bg: shift-color($value, $list-group-item-bg-scale);
$list-group-variant-color: shift-color($value, $list-group-item-color-scale);
@if (contrast-ratio($list-group-variant-bg, $list-group-variant-color) < $min-contrast-ratio) {
$list-group-variant-color: mix($value, color-contrast($list-group-variant-bg), abs($list-group-item-color-scale));
}
@include list-group-item-variant($state, $list-group-variant-bg, $list-group-variant-color);
}
// scss-docs-end list-group-modifiers

View File

@ -1,43 +0,0 @@
// Toggles
//
// Used in conjunction with global variables to enable certain theme features.
// Vendor
@import "vendor/rfs";
// Deprecate
@import "mixins/deprecate";
// Helpers
@import "mixins/breakpoints";
@import "mixins/color-scheme";
@import "mixins/image";
@import "mixins/resize";
@import "mixins/visually-hidden";
@import "mixins/reset-text";
@import "mixins/text-truncate";
// Utilities
@import "mixins/utilities";
// Components
@import "mixins/alert";
@import "mixins/backdrop";
@import "mixins/buttons";
@import "mixins/caret";
@import "mixins/pagination";
@import "mixins/lists";
@import "mixins/list-group";
@import "mixins/forms";
@import "mixins/table-variants";
// Skins
@import "mixins/border-radius";
@import "mixins/box-shadow";
@import "mixins/gradients";
@import "mixins/transition";
// Layout
@import "mixins/clearfix";
@import "mixins/container";
@import "mixins/grid";

View File

@ -1,209 +0,0 @@
// .modal-open - body class for killing the scroll
// .modal - container to scroll within
// .modal-dialog - positioning shell for the actual modal
// .modal-content - actual modal w/ bg and corners and stuff
// Container that the modal scrolls within
.modal {
position: fixed;
top: 0;
left: 0;
z-index: $zindex-modal;
display: none;
width: 100%;
height: 100%;
overflow-x: hidden;
overflow-y: auto;
// Prevent Chrome on Windows from adding a focus outline. For details, see
// https://github.com/twbs/bootstrap/pull/10951.
outline: 0;
// We deliberately don't use `-webkit-overflow-scrolling: touch;` due to a
// gnarly iOS Safari bug: https://bugs.webkit.org/show_bug.cgi?id=158342
// See also https://github.com/twbs/bootstrap/issues/17695
}
// Shell div to position the modal with bottom padding
.modal-dialog {
position: relative;
width: auto;
margin: $modal-dialog-margin;
// allow clicks to pass through for custom click handling to close modal
pointer-events: none;
// When fading in the modal, animate it to slide down
.modal.fade & {
@include transition($modal-transition);
transform: $modal-fade-transform;
}
.modal.show & {
transform: $modal-show-transform;
}
// When trying to close, animate focus to scale
.modal.modal-static & {
transform: $modal-scale-transform;
}
}
.modal-dialog-scrollable {
height: subtract(100%, $modal-dialog-margin * 2);
.modal-content {
max-height: 100%;
overflow: hidden;
}
.modal-body {
overflow-y: auto;
}
}
.modal-dialog-centered {
display: flex;
align-items: center;
min-height: subtract(100%, $modal-dialog-margin * 2);
}
// Actual modal
.modal-content {
position: relative;
display: flex;
flex-direction: column;
width: 100%; // Ensure `.modal-content` extends the full width of the parent `.modal-dialog`
// counteract the pointer-events: none; in the .modal-dialog
color: $modal-content-color;
pointer-events: auto;
background-color: $modal-content-bg;
background-clip: padding-box;
border: $modal-content-border-width solid $modal-content-border-color;
@include border-radius($modal-content-border-radius);
@include box-shadow($modal-content-box-shadow-xs);
// Remove focus outline from opened modal
outline: 0;
}
// Modal background
.modal-backdrop {
@include overlay-backdrop($zindex-modal-backdrop, $modal-backdrop-bg, $modal-backdrop-opacity);
}
// Modal header
// Top section of the modal w/ title and dismiss
.modal-header {
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: space-between; // Put modal header elements (title and dismiss) on opposite ends
padding: $modal-header-padding;
border-bottom: $modal-header-border-width solid $modal-header-border-color;
@include border-top-radius($modal-content-inner-border-radius);
.btn-close {
padding: ($modal-header-padding-y * .5) ($modal-header-padding-x * .5);
margin: ($modal-header-padding-y * -.5) ($modal-header-padding-x * -.5) ($modal-header-padding-y * -.5) auto;
}
}
// Title text within header
.modal-title {
margin-bottom: 0;
line-height: $modal-title-line-height;
}
// Modal body
// Where all modal content resides (sibling of .modal-header and .modal-footer)
.modal-body {
position: relative;
// Enable `flex-grow: 1` so that the body take up as much space as possible
// when there should be a fixed height on `.modal-dialog`.
flex: 1 1 auto;
padding: $modal-inner-padding;
}
// Footer (for actions)
.modal-footer {
display: flex;
flex-wrap: wrap;
flex-shrink: 0;
align-items: center; // vertically center
justify-content: flex-end; // Right align buttons with flex property because text-align doesn't work on flex items
padding: $modal-inner-padding - $modal-footer-margin-between * .5;
border-top: $modal-footer-border-width solid $modal-footer-border-color;
@include border-bottom-radius($modal-content-inner-border-radius);
// Place margin between footer elements
// This solution is far from ideal because of the universal selector usage,
// but is needed to fix https://github.com/twbs/bootstrap/issues/24800
> * {
margin: $modal-footer-margin-between * .5;
}
}
// Scale up the modal
@include media-breakpoint-up(sm) {
// Automatically set modal's width for larger viewports
.modal-dialog {
max-width: $modal-md;
margin: $modal-dialog-margin-y-sm-up auto;
}
.modal-dialog-scrollable {
height: subtract(100%, $modal-dialog-margin-y-sm-up * 2);
}
.modal-dialog-centered {
min-height: subtract(100%, $modal-dialog-margin-y-sm-up * 2);
}
.modal-content {
@include box-shadow($modal-content-box-shadow-sm-up);
}
.modal-sm { max-width: $modal-sm; }
}
@include media-breakpoint-up(lg) {
.modal-lg,
.modal-xl {
max-width: $modal-lg;
}
}
@include media-breakpoint-up(xl) {
.modal-xl { max-width: $modal-xl; }
}
// scss-docs-start modal-fullscreen-loop
@each $breakpoint in map-keys($grid-breakpoints) {
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);
$postfix: if($infix != "", $infix + "-down", "");
@include media-breakpoint-down($breakpoint) {
.modal-fullscreen#{$postfix} {
width: 100vw;
max-width: none;
height: 100%;
margin: 0;
.modal-content {
height: 100%;
border: 0;
@include border-radius(0);
}
.modal-header {
@include border-radius(0);
}
.modal-body {
overflow-y: auto;
}
.modal-footer {
@include border-radius(0);
}
}
}
}
// scss-docs-end modal-fullscreen-loop

View File

@ -1,139 +0,0 @@
// Base class
//
// Kickstart any navigation component with a set of style resets. Works with
// `<nav>`s, `<ul>`s or `<ol>`s.
.nav {
display: flex;
flex-wrap: wrap;
padding-left: 0;
margin-bottom: 0;
list-style: none;
}
.nav-link {
display: block;
padding: $nav-link-padding-y $nav-link-padding-x;
@include font-size($nav-link-font-size);
font-weight: $nav-link-font-weight;
color: $nav-link-color;
text-decoration: if($link-decoration == none, null, none);
@include transition($nav-link-transition);
&:hover,
&:focus {
color: $nav-link-hover-color;
text-decoration: if($link-hover-decoration == underline, none, null);
}
// Disabled state lightens text
&.disabled {
color: $nav-link-disabled-color;
pointer-events: none;
cursor: default;
}
}
//
// Tabs
//
.nav-tabs {
border-bottom: $nav-tabs-border-width solid $nav-tabs-border-color;
.nav-link {
margin-bottom: -$nav-tabs-border-width;
background: none;
border: $nav-tabs-border-width solid transparent;
@include border-top-radius($nav-tabs-border-radius);
&:hover,
&:focus {
border-color: $nav-tabs-link-hover-border-color;
// Prevents active .nav-link tab overlapping focus outline of previous/next .nav-link
isolation: isolate;
}
&.disabled {
color: $nav-link-disabled-color;
background-color: transparent;
border-color: transparent;
}
}
.nav-link.active,
.nav-item.show .nav-link {
color: $nav-tabs-link-active-color;
background-color: $nav-tabs-link-active-bg;
border-color: $nav-tabs-link-active-border-color;
}
.dropdown-menu {
// Make dropdown border overlap tab border
margin-top: -$nav-tabs-border-width;
// Remove the top rounded corners here since there is a hard edge above the menu
@include border-top-radius(0);
}
}
//
// Pills
//
.nav-pills {
.nav-link {
background: none;
border: 0;
@include border-radius($nav-pills-border-radius);
}
.nav-link.active,
.show > .nav-link {
color: $nav-pills-link-active-color;
@include gradient-bg($nav-pills-link-active-bg);
}
}
//
// Justified variants
//
.nav-fill {
> .nav-link,
.nav-item {
flex: 1 1 auto;
text-align: center;
}
}
.nav-justified {
> .nav-link,
.nav-item {
flex-basis: 0;
flex-grow: 1;
text-align: center;
}
}
.nav-fill,
.nav-justified {
.nav-item .nav-link {
width: 100%; // Make sure button will grow
}
}
// Tabbable tabs
//
// Hide tabbable panes to start, show them when `.active`
.tab-content {
> .tab-pane {
display: none;
}
> .active {
display: block;
}
}

View File

@ -1,335 +0,0 @@
// Contents
//
// Navbar
// Navbar brand
// Navbar nav
// Navbar text
// Responsive navbar
// Navbar position
// Navbar themes
// Navbar
//
// Provide a static navbar from which we expand to create full-width, fixed, and
// other navbar variations.
.navbar {
position: relative;
display: flex;
flex-wrap: wrap; // allow us to do the line break for collapsing content
align-items: center;
justify-content: space-between; // space out brand from logo
padding-top: $navbar-padding-y;
padding-right: $navbar-padding-x; // default: null
padding-bottom: $navbar-padding-y;
padding-left: $navbar-padding-x; // default: null
@include gradient-bg();
// Because flex properties aren't inherited, we need to redeclare these first
// few properties so that content nested within behave properly.
// The `flex-wrap` property is inherited to simplify the expanded navbars
%container-flex-properties {
display: flex;
flex-wrap: inherit;
align-items: center;
justify-content: space-between;
}
> .container,
> .container-fluid {
@extend %container-flex-properties;
}
@each $breakpoint, $container-max-width in $container-max-widths {
> .container#{breakpoint-infix($breakpoint, $container-max-widths)} {
@extend %container-flex-properties;
}
}
}
// Navbar brand
//
// Used for brand, project, or site names.
.navbar-brand {
padding-top: $navbar-brand-padding-y;
padding-bottom: $navbar-brand-padding-y;
margin-right: $navbar-brand-margin-end;
@include font-size($navbar-brand-font-size);
text-decoration: if($link-decoration == none, null, none);
white-space: nowrap;
&:hover,
&:focus {
text-decoration: if($link-hover-decoration == underline, none, null);
}
}
// Navbar nav
//
// Custom navbar navigation (doesn't require `.nav`, but does make use of `.nav-link`).
.navbar-nav {
display: flex;
flex-direction: column; // cannot use `inherit` to get the `.navbar`s value
padding-left: 0;
margin-bottom: 0;
list-style: none;
.nav-link {
padding-right: 0;
padding-left: 0;
}
.dropdown-menu {
position: static;
}
}
// Navbar text
//
//
.navbar-text {
padding-top: $nav-link-padding-y;
padding-bottom: $nav-link-padding-y;
}
// Responsive navbar
//
// Custom styles for responsive collapsing and toggling of navbar contents.
// Powered by the collapse Bootstrap JavaScript plugin.
// When collapsed, prevent the toggleable navbar contents from appearing in
// the default flexbox row orientation. Requires the use of `flex-wrap: wrap`
// on the `.navbar` parent.
.navbar-collapse {
flex-basis: 100%;
flex-grow: 1;
// For always expanded or extra full navbars, ensure content aligns itself
// properly vertically. Can be easily overridden with flex utilities.
align-items: center;
}
// Button for toggling the navbar when in its collapsed state
.navbar-toggler {
padding: $navbar-toggler-padding-y $navbar-toggler-padding-x;
@include font-size($navbar-toggler-font-size);
line-height: 1;
background-color: transparent; // remove default button style
border: $border-width solid transparent; // remove default button style
@include border-radius($navbar-toggler-border-radius);
@include transition($navbar-toggler-transition);
&:hover {
text-decoration: none;
}
&:focus {
text-decoration: none;
outline: 0;
box-shadow: 0 0 0 $navbar-toggler-focus-width;
}
}
// Keep as a separate element so folks can easily override it with another icon
// or image file as needed.
.navbar-toggler-icon {
display: inline-block;
width: 1.5em;
height: 1.5em;
vertical-align: middle;
background-repeat: no-repeat;
background-position: center;
background-size: 100%;
}
.navbar-nav-scroll {
max-height: var(--#{$variable-prefix}scroll-height, 75vh);
overflow-y: auto;
}
// scss-docs-start navbar-expand-loop
// Generate series of `.navbar-expand-*` responsive classes for configuring
// where your navbar collapses.
.navbar-expand {
@each $breakpoint in map-keys($grid-breakpoints) {
$next: breakpoint-next($breakpoint, $grid-breakpoints);
$infix: breakpoint-infix($next, $grid-breakpoints);
// stylelint-disable-next-line scss/selector-no-union-class-name
&#{$infix} {
@include media-breakpoint-up($next) {
flex-wrap: nowrap;
justify-content: flex-start;
.navbar-nav {
flex-direction: row;
.dropdown-menu {
position: absolute;
}
.nav-link {
padding-right: $navbar-nav-link-padding-x;
padding-left: $navbar-nav-link-padding-x;
}
}
.navbar-nav-scroll {
overflow: visible;
}
.navbar-collapse {
display: flex !important; // stylelint-disable-line declaration-no-important
flex-basis: auto;
}
.navbar-toggler {
display: none;
}
.offcanvas-header {
display: none;
}
.offcanvas {
position: inherit;
bottom: 0;
z-index: 1000;
flex-grow: 1;
visibility: visible !important; // stylelint-disable-line declaration-no-important
background-color: transparent;
border-right: 0;
border-left: 0;
@include transition(none);
transform: none;
}
.offcanvas-top,
.offcanvas-bottom {
height: auto;
border-top: 0;
border-bottom: 0;
}
.offcanvas-body {
display: flex;
flex-grow: 0;
padding: 0;
overflow-y: visible;
}
}
}
}
}
// scss-docs-end navbar-expand-loop
// Navbar themes
//
// Styles for switching between navbars with light or dark background.
// Dark links against a light background
.navbar-light {
.navbar-brand {
color: $navbar-light-brand-color;
&:hover,
&:focus {
color: $navbar-light-brand-hover-color;
}
}
.navbar-nav {
.nav-link {
color: $navbar-light-color;
&:hover,
&:focus {
color: $navbar-light-hover-color;
}
&.disabled {
color: $navbar-light-disabled-color;
}
}
.show > .nav-link,
.nav-link.active {
color: $navbar-light-active-color;
}
}
.navbar-toggler {
color: $navbar-light-color;
border-color: $navbar-light-toggler-border-color;
}
.navbar-toggler-icon {
background-image: escape-svg($navbar-light-toggler-icon-bg);
}
.navbar-text {
color: $navbar-light-color;
a,
a:hover,
a:focus {
color: $navbar-light-active-color;
}
}
}
// White links against a dark background
.navbar-dark {
.navbar-brand {
color: $navbar-dark-brand-color;
&:hover,
&:focus {
color: $navbar-dark-brand-hover-color;
}
}
.navbar-nav {
.nav-link {
color: $navbar-dark-color;
&:hover,
&:focus {
color: $navbar-dark-hover-color;
}
&.disabled {
color: $navbar-dark-disabled-color;
}
}
.show > .nav-link,
.nav-link.active {
color: $navbar-dark-active-color;
}
}
.navbar-toggler {
color: $navbar-dark-color;
border-color: $navbar-dark-toggler-border-color;
}
.navbar-toggler-icon {
background-image: escape-svg($navbar-dark-toggler-icon-bg);
}
.navbar-text {
color: $navbar-dark-color;
a,
a:hover,
a:focus {
color: $navbar-dark-active-color;
}
}
}

View File

@ -1,83 +0,0 @@
.offcanvas {
position: fixed;
bottom: 0;
z-index: $zindex-offcanvas;
display: flex;
flex-direction: column;
max-width: 100%;
color: $offcanvas-color;
visibility: hidden;
background-color: $offcanvas-bg-color;
background-clip: padding-box;
outline: 0;
@include box-shadow($offcanvas-box-shadow);
@include transition(transform $offcanvas-transition-duration ease-in-out);
}
.offcanvas-backdrop {
@include overlay-backdrop($zindex-offcanvas-backdrop, $offcanvas-backdrop-bg, $offcanvas-backdrop-opacity);
}
.offcanvas-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: $offcanvas-padding-y $offcanvas-padding-x;
.btn-close {
padding: ($offcanvas-padding-y * .5) ($offcanvas-padding-x * .5);
margin-top: $offcanvas-padding-y * -.5;
margin-right: $offcanvas-padding-x * -.5;
margin-bottom: $offcanvas-padding-y * -.5;
}
}
.offcanvas-title {
margin-bottom: 0;
line-height: $offcanvas-title-line-height;
}
.offcanvas-body {
flex-grow: 1;
padding: $offcanvas-padding-y $offcanvas-padding-x;
overflow-y: auto;
}
.offcanvas-start {
top: 0;
left: 0;
width: $offcanvas-horizontal-width;
border-right: $offcanvas-border-width solid $offcanvas-border-color;
transform: translateX(-100%);
}
.offcanvas-end {
top: 0;
right: 0;
width: $offcanvas-horizontal-width;
border-left: $offcanvas-border-width solid $offcanvas-border-color;
transform: translateX(100%);
}
.offcanvas-top {
top: 0;
right: 0;
left: 0;
height: $offcanvas-vertical-height;
max-height: 100%;
border-bottom: $offcanvas-border-width solid $offcanvas-border-color;
transform: translateY(-100%);
}
.offcanvas-bottom {
right: 0;
left: 0;
height: $offcanvas-vertical-height;
max-height: 100%;
border-top: $offcanvas-border-width solid $offcanvas-border-color;
transform: translateY(100%);
}
.offcanvas.show {
transform: none;
}

View File

@ -1,64 +0,0 @@
.pagination {
display: flex;
@include list-unstyled();
}
.page-link {
position: relative;
display: block;
color: $pagination-color;
text-decoration: if($link-decoration == none, null, none);
background-color: $pagination-bg;
border: $pagination-border-width solid $pagination-border-color;
@include transition($pagination-transition);
&:hover {
z-index: 2;
color: $pagination-hover-color;
text-decoration: if($link-hover-decoration == underline, none, null);
background-color: $pagination-hover-bg;
border-color: $pagination-hover-border-color;
}
&:focus {
z-index: 3;
color: $pagination-focus-color;
background-color: $pagination-focus-bg;
outline: $pagination-focus-outline;
box-shadow: $pagination-focus-box-shadow;
}
}
.page-item {
&:not(:first-child) .page-link {
margin-left: $pagination-margin-start;
}
&.active .page-link {
z-index: 3;
color: $pagination-active-color;
@include gradient-bg($pagination-active-bg);
border-color: $pagination-active-border-color;
}
&.disabled .page-link {
color: $pagination-disabled-color;
pointer-events: none;
background-color: $pagination-disabled-bg;
border-color: $pagination-disabled-border-color;
}
}
//
// Sizing
//
@include pagination-size($pagination-padding-y, $pagination-padding-x, null, $pagination-border-radius);
.pagination-lg {
@include pagination-size($pagination-padding-y-lg, $pagination-padding-x-lg, $font-size-lg, $pagination-border-radius-lg);
}
.pagination-sm {
@include pagination-size($pagination-padding-y-sm, $pagination-padding-x-sm, $font-size-sm, $pagination-border-radius-sm);
}

View File

@ -1,51 +0,0 @@
.placeholder {
display: inline-block;
min-height: 1em;
vertical-align: middle;
cursor: wait;
background-color: currentColor;
opacity: $placeholder-opacity-max;
&.btn::before {
display: inline-block;
content: "";
}
}
// Sizing
.placeholder-xs {
min-height: .6em;
}
.placeholder-sm {
min-height: .8em;
}
.placeholder-lg {
min-height: 1.2em;
}
// Animation
.placeholder-glow {
.placeholder {
animation: placeholder-glow 2s ease-in-out infinite;
}
}
@keyframes placeholder-glow {
50% {
opacity: $placeholder-opacity-min;
}
}
.placeholder-wave {
mask-image: linear-gradient(130deg, $black 55%, rgba(0, 0, 0, (1 - $placeholder-opacity-min)) 75%, $black 95%);
mask-size: 200% 100%;
animation: placeholder-wave 2s linear infinite;
}
@keyframes placeholder-wave {
100% {
mask-position: -200% 0%;
}
}

View File

@ -1,158 +0,0 @@
.popover {
position: absolute;
top: 0;
left: 0 #{"/* rtl:ignore */"};
z-index: $zindex-popover;
display: block;
max-width: $popover-max-width;
// Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.
// So reset our font and text properties to avoid inheriting weird values.
@include reset-text();
@include font-size($popover-font-size);
// Allow breaking very long words so they don't overflow the popover's bounds
word-wrap: break-word;
background-color: $popover-bg;
background-clip: padding-box;
border: $popover-border-width solid $popover-border-color;
@include border-radius($popover-border-radius);
@include box-shadow($popover-box-shadow);
.popover-arrow {
position: absolute;
display: block;
width: $popover-arrow-width;
height: $popover-arrow-height;
&::before,
&::after {
position: absolute;
display: block;
content: "";
border-color: transparent;
border-style: solid;
}
}
}
.bs-popover-top {
> .popover-arrow {
bottom: subtract(-$popover-arrow-height, $popover-border-width);
&::before {
bottom: 0;
border-width: $popover-arrow-height ($popover-arrow-width * .5) 0;
border-top-color: $popover-arrow-outer-color;
}
&::after {
bottom: $popover-border-width;
border-width: $popover-arrow-height ($popover-arrow-width * .5) 0;
border-top-color: $popover-arrow-color;
}
}
}
.bs-popover-end {
> .popover-arrow {
left: subtract(-$popover-arrow-height, $popover-border-width);
width: $popover-arrow-height;
height: $popover-arrow-width;
&::before {
left: 0;
border-width: ($popover-arrow-width * .5) $popover-arrow-height ($popover-arrow-width * .5) 0;
border-right-color: $popover-arrow-outer-color;
}
&::after {
left: $popover-border-width;
border-width: ($popover-arrow-width * .5) $popover-arrow-height ($popover-arrow-width * .5) 0;
border-right-color: $popover-arrow-color;
}
}
}
.bs-popover-bottom {
> .popover-arrow {
top: subtract(-$popover-arrow-height, $popover-border-width);
&::before {
top: 0;
border-width: 0 ($popover-arrow-width * .5) $popover-arrow-height ($popover-arrow-width * .5);
border-bottom-color: $popover-arrow-outer-color;
}
&::after {
top: $popover-border-width;
border-width: 0 ($popover-arrow-width * .5) $popover-arrow-height ($popover-arrow-width * .5);
border-bottom-color: $popover-arrow-color;
}
}
// This will remove the popover-header's border just below the arrow
.popover-header::before {
position: absolute;
top: 0;
left: 50%;
display: block;
width: $popover-arrow-width;
margin-left: -$popover-arrow-width * .5;
content: "";
border-bottom: $popover-border-width solid $popover-header-bg;
}
}
.bs-popover-start {
> .popover-arrow {
right: subtract(-$popover-arrow-height, $popover-border-width);
width: $popover-arrow-height;
height: $popover-arrow-width;
&::before {
right: 0;
border-width: ($popover-arrow-width * .5) 0 ($popover-arrow-width * .5) $popover-arrow-height;
border-left-color: $popover-arrow-outer-color;
}
&::after {
right: $popover-border-width;
border-width: ($popover-arrow-width * .5) 0 ($popover-arrow-width * .5) $popover-arrow-height;
border-left-color: $popover-arrow-color;
}
}
}
.bs-popover-auto {
&[data-popper-placement^="top"] {
@extend .bs-popover-top;
}
&[data-popper-placement^="right"] {
@extend .bs-popover-end;
}
&[data-popper-placement^="bottom"] {
@extend .bs-popover-bottom;
}
&[data-popper-placement^="left"] {
@extend .bs-popover-start;
}
}
// Offset the popover to account for the popover arrow
.popover-header {
padding: $popover-header-padding-y $popover-header-padding-x;
margin-bottom: 0; // Reset the default from Reboot
@include font-size($font-size-base);
color: $popover-header-color;
background-color: $popover-header-bg;
border-bottom: $popover-border-width solid $popover-border-color;
@include border-top-radius($popover-inner-border-radius);
&:empty {
display: none;
}
}
.popover-body {
padding: $popover-body-padding-y $popover-body-padding-x;
color: $popover-body-color;
}

View File

@ -1,48 +0,0 @@
// Disable animation if transitions are disabled
// scss-docs-start progress-keyframes
@if $enable-transitions {
@keyframes progress-bar-stripes {
0% { background-position-x: $progress-height; }
}
}
// scss-docs-end progress-keyframes
.progress {
display: flex;
height: $progress-height;
overflow: hidden; // force rounded corners by cropping it
@include font-size($progress-font-size);
background-color: $progress-bg;
@include border-radius($progress-border-radius);
@include box-shadow($progress-box-shadow);
}
.progress-bar {
display: flex;
flex-direction: column;
justify-content: center;
overflow: hidden;
color: $progress-bar-color;
text-align: center;
white-space: nowrap;
background-color: $progress-bar-bg;
@include transition($progress-bar-transition);
}
.progress-bar-striped {
@include gradient-striped();
background-size: $progress-height $progress-height;
}
@if $enable-transitions {
.progress-bar-animated {
animation: $progress-bar-animation-timing progress-bar-stripes;
@if $enable-reduced-motion {
@media (prefers-reduced-motion: reduce) {
animation: none;
}
}
}
}

View File

@ -1,625 +0,0 @@
// stylelint-disable declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix
// Reboot
//
// Normalization of HTML elements, manually forked from Normalize.css to remove
// styles targeting irrelevant browsers while applying new styles.
//
// Normalize is licensed MIT. https://github.com/necolas/normalize.css
// Document
//
// Change from `box-sizing: content-box` so that `width` is not affected by `padding` or `border`.
*,
*::before,
*::after {
box-sizing: border-box;
}
// Root
//
// Ability to the value of the root font sizes, affecting the value of `rem`.
// null by default, thus nothing is generated.
:root {
@if $font-size-root != null {
font-size: var(--#{$variable-prefix}root-font-size);
}
@if $enable-smooth-scroll {
@media (prefers-reduced-motion: no-preference) {
scroll-behavior: smooth;
}
}
}
// Body
//
// 1. Remove the margin in all browsers.
// 2. As a best practice, apply a default `background-color`.
// 3. Prevent adjustments of font size after orientation changes in iOS.
// 4. Change the default tap highlight to be completely transparent in iOS.
// scss-docs-start reboot-body-rules
body {
margin: 0; // 1
font-family: var(--#{$variable-prefix}body-font-family);
@include font-size(var(--#{$variable-prefix}body-font-size));
font-weight: var(--#{$variable-prefix}body-font-weight);
line-height: var(--#{$variable-prefix}body-line-height);
color: var(--#{$variable-prefix}body-color);
text-align: var(--#{$variable-prefix}body-text-align);
background-color: var(--#{$variable-prefix}body-bg); // 2
-webkit-text-size-adjust: 100%; // 3
-webkit-tap-highlight-color: rgba($black, 0); // 4
}
// scss-docs-end reboot-body-rules
// Content grouping
//
// 1. Reset Firefox's gray color
// 2. Set correct height and prevent the `size` attribute to make the `hr` look like an input field
hr {
margin: $hr-margin-y 0;
color: $hr-color; // 1
background-color: currentColor;
border: 0;
opacity: $hr-opacity;
}
hr:not([size]) {
height: $hr-height; // 2
}
// Typography
//
// 1. Remove top margins from headings
// By default, `<h1>`-`<h6>` all receive top and bottom margins. We nuke the top
// margin for easier control within type scales as it avoids margin collapsing.
%heading {
margin-top: 0; // 1
margin-bottom: $headings-margin-bottom;
font-family: $headings-font-family;
font-style: $headings-font-style;
font-weight: $headings-font-weight;
line-height: $headings-line-height;
color: $headings-color;
}
h1 {
@extend %heading;
@include font-size($h1-font-size);
}
h2 {
@extend %heading;
@include font-size($h2-font-size);
}
h3 {
@extend %heading;
@include font-size($h3-font-size);
}
h4 {
@extend %heading;
@include font-size($h4-font-size);
}
h5 {
@extend %heading;
@include font-size($h5-font-size);
}
h6 {
@extend %heading;
@include font-size($h6-font-size);
}
// Reset margins on paragraphs
//
// Similarly, the top margin on `<p>`s get reset. However, we also reset the
// bottom margin to use `rem` units instead of `em`.
p {
margin-top: 0;
margin-bottom: $paragraph-margin-bottom;
}
// Abbreviations
//
// 1. Duplicate behavior to the data-bs-* attribute for our tooltip plugin
// 2. Add the correct text decoration in Chrome, Edge, Opera, and Safari.
// 3. Add explicit cursor to indicate changed behavior.
// 4. Prevent the text-decoration to be skipped.
abbr[title],
abbr[data-bs-original-title] { // 1
text-decoration: underline dotted; // 2
cursor: help; // 3
text-decoration-skip-ink: none; // 4
}
// Address
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
// Lists
ol,
ul {
padding-left: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: $dt-font-weight;
}
// 1. Undo browser default
dd {
margin-bottom: .5rem;
margin-left: 0; // 1
}
// Blockquote
blockquote {
margin: 0 0 1rem;
}
// Strong
//
// Add the correct font weight in Chrome, Edge, and Safari
b,
strong {
font-weight: $font-weight-bolder;
}
// Small
//
// Add the correct font size in all browsers
small {
@include font-size($small-font-size);
}
// Mark
mark {
padding: $mark-padding;
background-color: $mark-bg;
}
// Sub and Sup
//
// Prevent `sub` and `sup` elements from affecting the line height in
// all browsers.
sub,
sup {
position: relative;
@include font-size($sub-sup-font-size);
line-height: 0;
vertical-align: baseline;
}
sub { bottom: -.25em; }
sup { top: -.5em; }
// Links
a {
color: $link-color;
text-decoration: $link-decoration;
&:hover {
color: $link-hover-color;
text-decoration: $link-hover-decoration;
}
}
// And undo these styles for placeholder links/named anchors (without href).
// It would be more straightforward to just use a[href] in previous block, but that
// causes specificity issues in many other styles that are too complex to fix.
// See https://github.com/twbs/bootstrap/issues/19402
a:not([href]):not([class]) {
&,
&:hover {
color: inherit;
text-decoration: none;
}
}
// Code
pre,
code,
kbd,
samp {
font-family: $font-family-code;
@include font-size(1em); // Correct the odd `em` font sizing in all browsers.
direction: ltr #{"/* rtl:ignore */"};
unicode-bidi: bidi-override;
}
// 1. Remove browser default top margin
// 2. Reset browser default of `1em` to use `rem`s
// 3. Don't allow content to break outside
pre {
display: block;
margin-top: 0; // 1
margin-bottom: 1rem; // 2
overflow: auto; // 3
@include font-size($code-font-size);
color: $pre-color;
// Account for some code outputs that place code tags in pre tags
code {
@include font-size(inherit);
color: inherit;
word-break: normal;
}
}
code {
@include font-size($code-font-size);
color: $code-color;
word-wrap: break-word;
// Streamline the style when inside anchors to avoid broken underline and more
a > & {
color: inherit;
}
}
kbd {
padding: $kbd-padding-y $kbd-padding-x;
@include font-size($kbd-font-size);
color: $kbd-color;
background-color: $kbd-bg;
@include border-radius($border-radius-sm);
kbd {
padding: 0;
@include font-size(1em);
font-weight: $nested-kbd-font-weight;
}
}
// Figures
//
// Apply a consistent margin strategy (matches our type styles).
figure {
margin: 0 0 1rem;
}
// Images and content
img,
svg {
vertical-align: middle;
}
// Tables
//
// Prevent double borders
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: $table-cell-padding-y;
padding-bottom: $table-cell-padding-y;
color: $table-caption-color;
text-align: left;
}
// 1. Removes font-weight bold by inheriting
// 2. Matches default `<td>` alignment by inheriting `text-align`.
// 3. Fix alignment for Safari
th {
font-weight: $table-th-font-weight; // 1
text-align: inherit; // 2
text-align: -webkit-match-parent; // 3
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
// Forms
//
// 1. Allow labels to use `margin` for spacing.
label {
display: inline-block; // 1
}
// Remove the default `border-radius` that macOS Chrome adds.
// See https://github.com/twbs/bootstrap/issues/24093
button {
// stylelint-disable-next-line property-disallowed-list
border-radius: 0;
}
// Explicitly remove focus outline in Chromium when it shouldn't be
// visible (e.g. as result of mouse click or touch tap). It already
// should be doing this automatically, but seems to currently be
// confused and applies its very visible two-tone outline anyway.
button:focus:not(:focus-visible) {
outline: 0;
}
// 1. Remove the margin in Firefox and Safari
input,
button,
select,
optgroup,
textarea {
margin: 0; // 1
font-family: inherit;
@include font-size(inherit);
line-height: inherit;
}
// Remove the inheritance of text transform in Firefox
button,
select {
text-transform: none;
}
// Set the cursor for non-`<button>` buttons
//
// Details at https://github.com/twbs/bootstrap/pull/30562
[role="button"] {
cursor: pointer;
}
select {
// Remove the inheritance of word-wrap in Safari.
// See https://github.com/twbs/bootstrap/issues/24990
word-wrap: normal;
// Undo the opacity change from Chrome
&:disabled {
opacity: 1;
}
}
// Remove the dropdown arrow in Chrome from inputs built with datalists.
// See https://stackoverflow.com/a/54997118
[list]::-webkit-calendar-picker-indicator {
display: none;
}
// 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
// controls in Android 4.
// 2. Correct the inability to style clickable types in iOS and Safari.
// 3. Opinionated: add "hand" cursor to non-disabled button elements.
button,
[type="button"], // 1
[type="reset"],
[type="submit"] {
-webkit-appearance: button; // 2
@if $enable-button-pointers {
&:not(:disabled) {
cursor: pointer; // 3
}
}
}
// Remove inner border and padding from Firefox, but don't restore the outline like Normalize.
::-moz-focus-inner {
padding: 0;
border-style: none;
}
// 1. Textareas should really only resize vertically so they don't break their (horizontal) containers.
textarea {
resize: vertical; // 1
}
// 1. Browsers set a default `min-width: min-content;` on fieldsets,
// unlike e.g. `<div>`s, which have `min-width: 0;` by default.
// So we reset that to ensure fieldsets behave more like a standard block element.
// See https://github.com/twbs/bootstrap/issues/12359
// and https://html.spec.whatwg.org/multipage/#the-fieldset-and-legend-elements
// 2. Reset the default outline behavior of fieldsets so they don't affect page layout.
fieldset {
min-width: 0; // 1
padding: 0; // 2
margin: 0; // 2
border: 0; // 2
}
// 1. By using `float: left`, the legend will behave like a block element.
// This way the border of a fieldset wraps around the legend if present.
// 2. Fix wrapping bug.
// See https://github.com/twbs/bootstrap/issues/29712
legend {
float: left; // 1
width: 100%;
padding: 0;
margin-bottom: $legend-margin-bottom;
@include font-size($legend-font-size);
font-weight: $legend-font-weight;
line-height: inherit;
+ * {
clear: left; // 2
}
}
// Fix height of inputs with a type of datetime-local, date, month, week, or time
// See https://github.com/twbs/bootstrap/issues/18842
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
// 1. Correct the outline style in Safari.
// 2. This overrides the extra rounded corners on search inputs in iOS so that our
// `.form-control` class can properly style them. Note that this cannot simply
// be added to `.form-control` as it's not specific enough. For details, see
// https://github.com/twbs/bootstrap/issues/11586.
[type="search"] {
outline-offset: -2px; // 1
-webkit-appearance: textfield; // 2
}
// 1. A few input types should stay LTR
// See https://rtlstyling.com/posts/rtl-styling#form-inputs
// 2. RTL only output
// See https://rtlcss.com/learn/usage-guide/control-directives/#raw
/* rtl:raw:
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
*/
// Remove the inner padding in Chrome and Safari on macOS.
::-webkit-search-decoration {
-webkit-appearance: none;
}
// Remove padding around color pickers in webkit browsers
::-webkit-color-swatch-wrapper {
padding: 0;
}
// Inherit font family and line height for file input buttons
::file-selector-button {
font: inherit;
}
// 1. Change font properties to `inherit`
// 2. Correct the inability to style clickable types in iOS and Safari.
::-webkit-file-upload-button {
font: inherit; // 1
-webkit-appearance: button; // 2
}
// Correct element displays
output {
display: inline-block;
}
// Remove border from iframe
iframe {
border: 0;
}
// Summary
//
// 1. Add the correct display in all browsers
summary {
display: list-item; // 1
cursor: pointer;
}
// Progress
//
// Add the correct vertical alignment in Chrome, Firefox, and Opera.
progress {
vertical-align: baseline;
}
// Hidden attribute
//
// Always hide an element with the `hidden` HTML attribute.
[hidden] {
display: none !important;
}

Some files were not shown because too many files have changed in this diff Show More